package com.miaxis.wx.service.impl;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.miaxis.common.enums.OrderStatusEnum;
import com.miaxis.common.exception.CustomException;
import com.miaxis.common.sms.MD5Utils;
import com.miaxis.common.utils.StringUtils;
import com.miaxis.feign.dto.FilmDTO;
import com.miaxis.feign.dto.FilmMcpData;
import com.miaxis.feign.dto.FilmXdResult;
import com.miaxis.feign.dto.fulu.FuluCommonApiDTO;
import com.miaxis.feign.dto.fulu.FuluDTO;
import com.miaxis.feign.dto.fulu.FuluGoodsInfo;
import com.miaxis.feign.dto.fulu.FuluResult;
import com.miaxis.feign.service.IFuluService;
import com.miaxis.wx.dto.*;
import com.miaxis.system.service.ISysConfigService;
import com.miaxis.wx.service.IRefundRecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import com.miaxis.wx.mapper.WxOrderMapper;
import com.miaxis.wx.domain.WxOrder;
import com.miaxis.wx.service.IWxOrderService;

import javax.annotation.Resource;

import static com.miaxis.common.utils.OrderCodeFactory.getOrderCode;

/**
 * 电影订单Service业务层处理
 *
 * @author miaxis
 * @date 2021-05-07
 */
@Service
@Slf4j
public class WxOrderServiceImpl extends ServiceImpl<WxOrderMapper, WxOrder> implements IWxOrderService {
    @Resource
    private WxOrderMapper wxOrderMapper;


    @Autowired
    private ISysConfigService configService;
    @Autowired
    private IRefundRecordService refundRecordService;
    @Autowired
    private IFuluService fuluService;
       @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Value("${film.notifyUrl}")
    private  String notifyUrl ;



    @Value("${app.appid}")
    private String appid;
    @Value("${film.appKey}")
    private  String appKey ;
    @Value("${film.appSecret}")
    private  String appSecret ;
    @Value("${film.v1Url}")
    private  String v1Url ;
    @Value("${film.v2Url}")
    private  String v2Url ;


    @Value("${fulu.appKey}")
    private  String fuluAppKey ;
    @Value("${fulu.appSecret}")
    private  String fuluAppSecret ;




    /**
     * 查询电影订单列表
     *
     * @param wxOrder 电影订单
     * @return 电影订单
     */
    @Override
    public List<WxOrder> selectWxOrderList(WxOrder wxOrder){
        return wxOrderMapper.selectWxOrderList(wxOrder);
    }

    @Override
    public WxOrder getByOutTradeNo(String outTradeNo) {
        return wxOrderMapper.getByOutTradeNo(outTradeNo);
    }

    @Override
    public String  excuteFilmApi(FilmDTO filmDTO)  {
        String resultData ="";
        // 创建一个http客户端
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        try {
            HttpPost post = null;
            if ("api/automation/orderHandle".equals(filmDTO.getUrl())) {
                post = new HttpPost(v1Url+filmDTO.getUrl());
            }else{
                post = new HttpPost(v2Url+filmDTO.getUrl());
            }
            post.setHeader("Content-Type","application/x-www-form-urlencoded");
            Map<String, Object> sortMap = new TreeMap<String, Object>();
            String time = String.valueOf(System.currentTimeMillis()/1000);
            sortMap.put("appKey",appKey);
            sortMap.put("time",time);
            //1 将数据拆分成 treemap存储
            if (!StringUtils.isEmpty(filmDTO.getParamData())){
                String[] keyValueStr = filmDTO.getParamData().split("&");
                for(String keyValue : keyValueStr){
                    String[] arr = keyValue.split("=");
                    sortMap.put(arr[0],arr[1]) ;
                }
            }
            //2 读取treemap。按固定格式拼接，最后再拼接上 secret
            StringBuilder builder = new StringBuilder();
            for (Map.Entry<String, Object> s : sortMap.entrySet()) {
                String k = s.getKey();
                Object v = s.getValue();
                builder.append(k).append("=").append(v).append("&");
            }
            builder.append("appSecret="+appSecret);
            //3 将最后拼接出来的sign传 md5加密
            String sign = MD5Utils.MD5Encode(builder.toString());
            List<BasicNameValuePair> pairList = new ArrayList<BasicNameValuePair>();
            // 迭代Map-->取出key,value放到BasicNameValuePair对象中-->添加到list中
            for (Map.Entry entry : sortMap.entrySet()) {
                pairList.add(new BasicNameValuePair(String.valueOf(entry.getKey()) ,String.valueOf(entry.getValue())));
            }
            pairList.add(new BasicNameValuePair("sign",sign));
            UrlEncodedFormEntity uefe = new UrlEncodedFormEntity(pairList, "utf-8");
            post.setEntity(uefe);

            // 发送post请求
            HttpResponse response = httpClient.execute(post);

            // 状态码为：200
            if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
                // 返回数据：
                resultData = EntityUtils.toString(response.getEntity(),"UTF-8");
                return resultData;
            }else{
                throw new RuntimeException("接口连接失败！");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("接口连接失败！");
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                throw new RuntimeException("CloseableHttpClient 关闭失败！");
            }
        }

    }

    @Override
    public List<WxOrder> selectOrderList(WxOrderListDTO wxOrderListDTO) {
        return wxOrderMapper.selectOrderList(wxOrderListDTO);
    }

    @Override
    public Integer getPrice(String cinemaId, String showId, int ticketType, FilmWxOrderJsonData wxOrderJsonData) {

        FilmDTO filmDTO = new FilmDTO();
        filmDTO.setUrl("movieapi/movie-info/get-schedule-list");
        StringBuffer paramData =  new StringBuffer();
        paramData.append("cinemaId="+cinemaId);
        filmDTO.setParamData(paramData.toString());
        String result = this.excuteFilmApi(filmDTO);
        JSONObject jsonObject = JSONObject.parseObject(result);
        JSONObject  data = jsonObject.getJSONObject("data");
        JSONObject  discountRule = data.getJSONObject("discountRule");
        JSONArray list = data.getJSONArray("list");
        log.info(list.toJSONString());
        List<CinemaData> cinemaData = list.toJavaList(CinemaData.class);
        List<CinemaData> listdata = cinemaData.stream().filter(a -> showId.equals(a.getShowId())).collect(Collectors.toList());
        CinemaData realCinemaData = listdata.get(0);
        wxOrderJsonData.setCinemaData(realCinemaData);
        Integer netPrice = realCinemaData.getNetPrice();
        Integer realValue =0;
        if (ticketType == 1){
            Double upDiscountRate = discountRule.getDouble("upDiscountRate");
            Double downDiscountRate = discountRule.getDouble("downDiscountRate");
            String film_discount = configService.selectConfigByKey("film_discount");
            Double  chosenDiscount = netPrice >3900 ? upDiscountRate:downDiscountRate;
            Double aDouble = Double.valueOf(film_discount);
            Double dDouble = netPrice * chosenDiscount * aDouble;
            realValue = dDouble.intValue();
        }else if (ticketType == 2){
            realValue = netPrice;
        }

        return realValue;


    }

    @Override
    public void createFilmOrder(WxOrder order, WxOrderCreateDTO wxOrderCreateDTO) {
        FilmWxOrderJsonData filmWxOrderJsonData = new FilmWxOrderJsonData();
        wxOrderCreateDTO.setThirdOrderId(order.getOutTradeNo());
        filmWxOrderJsonData.setWxOrderCreateDTO(wxOrderCreateDTO);
        Integer price = getPrice(wxOrderCreateDTO.getCinemaId(),wxOrderCreateDTO.getShowId(),wxOrderCreateDTO.getTicketType(),filmWxOrderJsonData);
        int number = wxOrderCreateDTO.getSeat().split(",").length;
        order.setOrderDataJson(JSONObject.toJSONString(filmWxOrderJsonData));
        order.setTotal(price*number);
    }

    @Override
    public void createFuluOrder(WxOrder order, WxOrderCreateFuluDTO wxOrderCreateDTO) {
        FuluWxOrderJsonData fuluWxOrderJsonData = new FuluWxOrderJsonData();
        wxOrderCreateDTO.setCustomer_order_no(order.getOutTradeNo());
        fuluWxOrderJsonData.setWxOrderCreateDTO(wxOrderCreateDTO);
        order.setOrderDataJson(JSONObject.toJSONString(fuluWxOrderJsonData));
        //调用福禄接口 获取产品详情对象
        FuluDTO fuluDTO = new FuluDTO();
        FuluCommonApiDTO fuluCommonApiDTO = new FuluCommonApiDTO();
        fuluCommonApiDTO.setMethod("fulu.goods.info.get");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("product_id",wxOrderCreateDTO.getProduct_id());
        fuluCommonApiDTO.setBiz_content(jsonObject.toJSONString());
        init(fuluDTO,fuluCommonApiDTO);
        FuluResult fuluResult = fuluService.fuluCommonApi(fuluDTO);
        if (fuluResult.getCode()!= 0){
            throw new CustomException("福禄接口调用失败:"+fuluResult.getMessage());
        }
        FuluGoodsInfo fuluGoodsInfo =   JSONObject.parseObject(fuluResult.getResult(), FuluGoodsInfo.class);
        fuluWxOrderJsonData.setFuluGoodsInfo(fuluGoodsInfo);
        String fuluVipDiscount = configService.selectConfigByKey("fulu_vip_discount");
        Double fuluVipDiscountDoubleValue = Double.valueOf(fuluVipDiscount);
        Double v =fuluGoodsInfo.getPurchase_price()* fuluVipDiscountDoubleValue * wxOrderCreateDTO.getBuy_num()* 100;
        order.setTotal(v.intValue());
    }

    @Override
    public void init(FuluDTO fuluDTO, FuluCommonApiDTO fuluCommonApiDTO) {
        fuluDTO.setApp_key(fuluAppKey);
        fuluDTO.setMethod(fuluCommonApiDTO.getMethod());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        fuluDTO.setTimestamp(simpleDateFormat.format(new Date()));
        fuluDTO.setVersion("2.0");
        fuluDTO.setFormat("json");
        fuluDTO.setCharset("utf-8");
        fuluDTO.setSign_type("md5");
        fuluDTO.setApp_auth_token("");
        fuluDTO.setBiz_content(fuluCommonApiDTO.getBiz_content());
        String str = JSONObject.toJSONString(fuluDTO);
        char[] s = str.toCharArray();
        Arrays.sort(s);
        String outputSignOriginalStr = new String(s) + fuluAppSecret;
        String sign = MD5Utils.MD5Encode(outputSignOriginalStr);
        fuluDTO.setSign(sign);
    }

    @Override
    public void buyFilmOrder(WxOrder wxOrder) {
        String orderDataJson = wxOrder.getOrderDataJson();
        FilmWxOrderJsonData wxOrderJsonData = JSONObject.parseObject(orderDataJson, FilmWxOrderJsonData.class);
        if (wxOrderJsonData != null && wxOrderJsonData.getWxOrderNotifyDTO() == null){
            threadPoolTaskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    WxOrderCreateDTO wxOrderCreateDTO = wxOrderJsonData.getWxOrderCreateDTO();
                    FilmDTO filmDTO = new FilmDTO();
                    if (wxOrderCreateDTO.getTicketType() ==1){
                        filmDTO.setUrl("api/order/create");
                    }else if (wxOrderCreateDTO.getTicketType() ==2){
                        filmDTO.setUrl("api/order/create-soon-order");
                    }

                    StringBuffer paramData =  new StringBuffer();
                    paramData.append("showId="+wxOrderCreateDTO.getShowId()+"&");
                    paramData.append("seat="+wxOrderCreateDTO.getSeat()+"&");
                    if (wxOrderCreateDTO.getReservedPhone() != null){
                        paramData.append("reservedPhone="+wxOrderCreateDTO.getReservedPhone()+"&");
                    }
                    paramData.append("thirdOrderId="+wxOrderCreateDTO.getThirdOrderId()+"&");
                    paramData.append("notifyUrl="+notifyUrl+"&");
                    if (wxOrderCreateDTO.getSeatId() != null){
                        paramData.append("seatId="+wxOrderCreateDTO.getSeatId()+"&");
                    }
                    if (wxOrderCreateDTO.getSeatNo() != null){
                        paramData.append("seatNo="+wxOrderCreateDTO.getSeatNo()+"&");
                    }
                    paramData.append("acceptChangeSeat="+wxOrderCreateDTO.getAcceptChangeSeat());
                    filmDTO.setParamData(paramData.toString());

                    String s = excuteFilmApi(filmDTO);
                    log.info("电影下单返回值:"+s);
                    FilmXdResult filmXdResult = JSONObject.parseObject(s, FilmXdResult.class);
                    //如果返回值不是200 ，则调用退款流程
                    if (filmXdResult.getCode()!=200){
                        String refundCode = getOrderCode(null);
                        wxOrder.setOrderStatus(OrderStatusEnum.FAILD.getCode());
                        wxOrder.setOutRefundNo(refundCode);
                        try {
                            refundRecordService.refund(wxOrder,refundCode,"电影购票失败,原因:"+filmXdResult.getMessage());
                        } catch (Exception e) {
                            throw new CustomException("退款失败");
                        }
                    }else {
                        wxOrder.setOrderStatus(OrderStatusEnum.PROCESSING.getCode());
                        if (filmXdResult.getData().getTicket()!= null){
                            wxOrder.setOrderStatus(OrderStatusEnum.SUCCESS.getCode());
                            FilmMcpData filmMcpData = filmXdResult.getData();
                            wxOrderJsonData.setFilmMcpData(filmMcpData);
                            wxOrder.setOrderDataJson(JSONObject.toJSONString(wxOrderJsonData));

                        }
                    }


                    updateById(wxOrder);

                }
            });
        }

    }

    @Override
    public void buyFuluOrder(WxOrder wxOrder) {
        String orderDataJson = wxOrder.getOrderDataJson();
        FuluWxOrderJsonData wxOrderJsonData = JSONObject.parseObject(orderDataJson, FuluWxOrderJsonData.class);
        if (wxOrderJsonData != null && wxOrderJsonData.getWxFuluOrderDetailDTO()== null){
            threadPoolTaskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    WxOrderCreateFuluDTO wxOrderCreateDTO = wxOrderJsonData.getWxOrderCreateDTO();
                    //调用福禄下单接口
                    FuluDTO fuluDTO = new FuluDTO();
                    FuluCommonApiDTO fuluCommonApiDTO = new FuluCommonApiDTO();
                    fuluCommonApiDTO.setMethod("fulu.order.direct.add");
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("product_id",wxOrderCreateDTO.getProduct_id());
                    jsonObject.put("customer_order_no",wxOrderCreateDTO.getCustomer_order_no());
                    jsonObject.put("charge_account",wxOrderCreateDTO.getCharge_account());
                    jsonObject.put("buy_num",wxOrderCreateDTO.getBuy_num());
                    fuluCommonApiDTO.setBiz_content(jsonObject.toJSONString());
                    FuluResult fuluResult = fuluService.fuluCommonApi(fuluDTO);
                    log.info("福禄下单返回值:"+JSONObject.toJSONString(fuluResult));
                    //如果返回值不是0 ，则调用退款流程
                    if (fuluResult.getCode() != 0){
                        String refundCode = getOrderCode(null);
                        wxOrder.setOrderStatus(OrderStatusEnum.FAILD.getCode());
                        wxOrder.setOutRefundNo(refundCode);
                        try {
                            refundRecordService.refund(wxOrder,refundCode,"商品购买失败,原因:"+fuluResult.getMessage());
                        } catch (Exception e) {
                            throw new CustomException("退款失败");
                        }
                    }else {
                        wxOrder.setOrderStatus(OrderStatusEnum.PROCESSING.getCode());
                    }
                    //返回成功，则保存返回福禄订单详情到微信订单json传中
                    WxFuluOrderDetailDTO wxFuluOrderDetailDTO = JSONObject.parseObject(fuluResult.getResult(),WxFuluOrderDetailDTO.class);
                    wxOrderJsonData.setWxFuluOrderDetailDTO(wxFuluOrderDetailDTO);
                    wxOrder.setOrderDataJson(wxOrderJsonData.toString());
                    updateById(wxOrder);
                }
            });
        }

    }
}
