package com.iformall.controller.callback;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.Result;
import com.iformall.controller.base.BaseController;
import com.iformall.domain.po.*;
import com.iformall.enums.EnumCarCmd;
import com.iformall.enums.EnumCarVendor;
import com.iformall.enums.EnumCouponSendSendType;
import com.iformall.enums.EnumETCPCode;
import com.iformall.service.*;
import com.iformall.utils.DateUtils;
import com.iformall.utils.car.ETCPUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/carCallback")
public class WxCarETCPCallBackController extends BaseController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    WxParkService wxParkService;

    @Autowired
    WxCUserCarService wxCUserCarService;

    @Autowired
    WxMerchantService wxMerchantService;

    @Autowired
    WxCarCmdLogService wxCarCmdLogService;

    @Autowired
    WxCouponSendService wxCouponSendService;

    @Autowired
    WxCarPayRecordService wxCarPayRecordService;

    @Autowired
    WxCUserService wxCUserService;

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * ETCP 车辆入场通知
     * {
     * "synId": "4ebd80ff-cfcf-462a-94cb-727e9fa9547c",
     * "plateNumber": "渝 ATX061",
     * "parkName": "ETCP 智慧停车场",
     * "parkId": "1",
     * "entranceTime": "2017-08-20 12:59:54",
     * "userType": "76",
     * "pushTime": "2017-08-20 12:59:57",
     * "fixParkingId": "U7",
     * "remainingDays": "11"
     * }
     */
    @PostMapping(value = "/etcpParkInCallback")
    public Result etcpParkInCallback(@RequestBody Map<String, String> paramMap) {
        logger.info("["+getIpAddr()+"] etcpParkInCallback: " + paramMap.toString());

        doEtcpParkIn(paramMap);

        return new Result(EnumETCPCode.SUCCESS.getCode(), EnumETCPCode.SUCCESS.getMessage());
    }

    /**
     * ETCP 车辆出场通知
     * {
     * "synId": "fd92f645-880e-4c2a-9d7d-7081a2488181",
     * "plateNumber": "渝 ATX061",
     * "parkName": "ETCP 智慧停车场",
     * "parkId": "1",
     * "entranceTime": "2017-08-17 18:44:19",
     * "userType": "76",
     * "pushTime": "2017-08-20 11:57:51",
     * "exitTime": "2017-08-19 12:07:19",
     * "stayedTime": 148980,
     * "receivableFee": 0,
     * "paidServiceFee": 0,
     * "fixParkingId": "U7",
     * "remainingDays": "12"
     * }
     */
    @PostMapping(value = "/etcpParkOutCallback")
    public Result etcpParkOutCallback(@RequestBody Map<String, String> paramMap) {
        logger.info("["+getIpAddr()+"etcpParkOutCallback: " + paramMap.toString());

        doEtcpParkOut(paramMap);

        return new Result(EnumETCPCode.SUCCESS.getCode(), EnumETCPCode.SUCCESS.getMessage());
    }

    /**
     * ETCP 车辆解绑通知
     * {
     * "plateNumber": "渝 ATX061",
     * "time": "2017-08-20 11:57:51"
     * }
     */
    @PostMapping(value = "/etcpUnbindCarCallBack")
    public Result etcpUnbindCarCallBack(@RequestBody Map<String, String> paramMap) {
        logger.info("["+getIpAddr()+"etcpUnbindCarCallBack: " + paramMap.toString());
        String carNumber = paramMap.get("plateNumber");

        // TODO how to get the parkId

        Date currentDate = new Date();
        WxCarCmdLog wxCarCmdLog = new WxCarCmdLog();
        wxCarCmdLog.setVendorType(EnumCarVendor.CAR_ETCP.getCode());
        wxCarCmdLog.setCmdType(EnumCarCmd.CAR_ETCP_CALLBACK_UNBIND.getCode());
        wxCarCmdLog.setCmdJson(JSON.toJSONString(paramMap));
        wxCarCmdLog.setCreateDate(currentDate);
        wxCarCmdLog.setUpdateDate(currentDate);
        try {
            wxCarCmdLogService.saveOrUpdate(wxCarCmdLog);
        } catch (Exception e) {
            logger.error("etcpUnbindCarCallBack: 入库错误 " + paramMap.toString());
            return new Result(ErrorCode.DB_FAIL.getCode(), "入库错误" + paramMap.toString());
        }

        WxCUserCar userCarQ = new WxCUserCar();
        userCarQ.setVendorType(EnumCarVendor.CAR_ETCP.getCode());
        userCarQ.setCarNumber(carNumber);
        // 数据库里删除，保持同步
        try {
            wxCUserCarService.deleteByObj(userCarQ);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        // 营销 - 短信
        return new Result(EnumETCPCode.SUCCESS.getCode(), EnumETCPCode.SUCCESS.getMessage());
    }

    /**
     * ETCP 主动支付结果通知
     * {
     * "signment":"B8534D2E8FA2074C216CCEF087AA9954",
     * "payWayDesc":"微信",
     * "plateNumber": "渝 ATX061",
     * "orderId": "fd92f645-880e-4c2a-9d7d-7081a2488181",
     * "fee": 7.65,
     * "paidServiceFee": 0.07,
     * "coupon": 0,
     * "time": "2017-08-20 11:57:51"
     * "discountAmount":0,
     * "onceServiceFeePaid":0.0,
     * "couponCode":""
     * }
     */
    @PostMapping(value = "/etcpPaidCallback")
    public Result etcpPaidCallback(@RequestBody Map<String, String> paramMap) {
        logger.info("["+getIpAddr()+"etcpPaidCallback: " + paramMap.toString());
        String carNumber = paramMap.get("plateNumber");

        // 根据orderId获取入场信息，确定租户ID
        String orderId = paramMap.get(ETCPUtil.ETCP_ORDER_ID);
        String etcpTime = paramMap.get(ETCPUtil.ETCP_TIME);
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("synId", orderId);
        map.put("plateNumber", carNumber);
        String tenantId = wxCarCmdLogService.getTenantIdBySynId(map);
        /// if not found syn_id, maybe use user_car to get tenantId
        if(StringUtils.isBlank(tenantId)) {
            WxCUserCar queryOne = new WxCUserCar();
            queryOne.setCarNumber(carNumber);
            WxCUserCar userCar = wxCUserCarService.getOnlyOne(queryOne);
            if(userCar != null) {
                tenantId = userCar.getTenantId();
            }
        }

        // 检查是否有重复数据
        if(StringUtils.isNotBlank(tenantId)) {
            map.put("tenantId", tenantId);
        }
        String paidServiceFee = paramMap.get(ETCPUtil.ETCP_PAID_SERVICE_FEE);
        String fee = paramMap.get(ETCPUtil.ETCP_FEE);
        Date feeTime = null;

        if(StringUtils.isNotBlank(etcpTime)) {
            try {
                feeTime = dateFormat.parse(etcpTime);
            } catch (ParseException e) {
                logger.error("解析fee time出错" + etcpTime);
            }
        }
        map.put("plateNumber", carNumber);
        map.put("orderId", orderId);
        map.put("fee", fee);
        map.put("feeTime", etcpTime);
        WxCarCmdLog carCmdLog = wxCarCmdLogService.getByOrderId(map);
        if(carCmdLog != null) {
            logger.error("ETCP order paid 已入库： " + orderId);
        }

        Date currentDate = new Date();
        WxCarCmdLog wxCarCmdLog = new WxCarCmdLog();
        if(StringUtils.isNotBlank(tenantId)) {
            wxCarCmdLog.setTenantId(tenantId);
        }
        if(carCmdLog != null) {
            // 如果有15分钟的已支付的数据，自动覆盖
            wxCarCmdLog.setId(carCmdLog.getId());
        }
        wxCarCmdLog.setVendorType(EnumCarVendor.CAR_ETCP.getCode());
        wxCarCmdLog.setCmdType(EnumCarCmd.CAR_ETCP_CALLBACK_PAY_MANUAL.getCode());
        wxCarCmdLog.setCmdJson(JSON.toJSONString(paramMap));
        wxCarCmdLog.setCreateDate(currentDate);
        wxCarCmdLog.setUpdateDate(currentDate);
        try {
            wxCarCmdLogService.saveOrUpdate(wxCarCmdLog);
        } catch (Exception e) {
            logger.error("etcpPaidCallback: 入库错误 " + paramMap.toString());
            return new Result(ErrorCode.DB_FAIL.getCode(), "入库错误" + paramMap.toString());
        }

        try {
            // 保存WxCarPayRecord
            WxCarPayRecord record = new WxCarPayRecord();
            record.setSynId(orderId);
            record.setFee(fee);
            if(feeTime != null) {
                record.setFeeTime(feeTime);
            }
            record.setPaidServiceFee(paidServiceFee);
            record.setVendorType(wxCarCmdLog.getVendorType());
            record.setPlateNumber(carNumber);
            record.setTenantId(tenantId);

            WxCarPayRecord query = new WxCarPayRecord();
            query.setSynId(orderId);
            PageInfo<WxCarPayRecord> page = wxCarPayRecordService.findCarPayListByPage(query,1,2);
            if(page != null && page.getList().size() > 0){

                if(page.getList().size() >= 2){
                    wxCarPayRecordService.saveOrUpdate(record);
                } else {
                    WxCarPayRecord r = page.getList().get(0);
                    if(r.getFeeTime() == null) {
                        // 无缴费信息， 更新
                        record.setId(r.getId());
                        wxCarPayRecordService.saveOrUpdate(record);
                    } else {
                        // 缴费时间在15分钟以内，更新之前的数据, ETCP会把之前的缴费自动退款
                        if(DateUtils.isInDate15Mins(feeTime, r.getFeeTime())) {
                            record.setId(r.getId());
                        }
                        wxCarPayRecordService.saveOrUpdate(record);
                    }
                }
            } else {
                wxCarPayRecordService.saveOrUpdate(record);
            }
        } catch (Exception e) {
            logger.error("WxCarPayRecord: 缴费更新错误 " +e.getMessage()+", "+ paramMap.toString());
            //return new Result(ErrorCode.DB_FAIL.getCode(), "入库错误" + paramMap.toString());
        }

        // 营销 - 短信
        return new Result(EnumETCPCode.SUCCESS.getCode(), EnumETCPCode.SUCCESS.getMessage());
    }

    // @Async
    private boolean doEtcpParkIn(@RequestBody Map<String, String> paramMap) {
        Date currentDate = new Date();
        WxCarCmdLog wxCarCmdLog = new WxCarCmdLog();

        wxCarCmdLog.setVendorType(EnumCarVendor.CAR_ETCP.getCode());
        wxCarCmdLog.setCmdType(EnumCarCmd.CAR_ETCP_CALLBACK_PARK_IN.getCode());
        wxCarCmdLog.setCmdJson(JSON.toJSONString(paramMap));
        wxCarCmdLog.setCreateDate(currentDate);
        wxCarCmdLog.setUpdateDate(currentDate);

        String etcpParkId = paramMap.get(ETCPUtil.ETCP_PARK_ID);
        String tenantId = null;
        WxPark parkQ = new WxPark();
        parkQ.setVendorType(EnumCarVendor.CAR_ETCP.getCode());
        parkQ.setParkingId(etcpParkId);
        WxPark park = wxParkService.getByObj(parkQ);
        if (park == null) {
            logger.error("etcpParkInCallback: ETCP车场未找到" + etcpParkId);
            //return new Result(ErrorCode.CAR_PARK_NOT_FOUND.getCode(), "ETCP车场未找到"+ etcpParkId);
        } else {
            tenantId = park.getTenantId();
            wxCarCmdLog.setTenantId(park.getTenantId());
        }

        String carNumber = paramMap.get(ETCPUtil.ETCP_CAR_NUMBER);
        String synId = paramMap.get(ETCPUtil.ETCP_SYN_ID);
        String parkId = paramMap.get(ETCPUtil.ETCP_PARK_ID);
        String parkName = paramMap.get(ETCPUtil.ETCP_PARK_NAME);
        String userType = paramMap.get(ETCPUtil.ETCP_USER_TYPE);
        String entranceTime = paramMap.get(ETCPUtil.ETCP_ENTRANCE_TIME);
        String fixParkingId = paramMap.get(ETCPUtil.ETCP_FIX_PARKING_ID);
        String remainingDays = paramMap.get(ETCPUtil.ETCP_REMAINING_DAYS);

        // 检查是否有重复数据
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("synId", synId);
        map.put("cmdType", EnumCarCmd.CAR_ETCP_CALLBACK_PARK_IN.getCode());
        if(tenantId != null) {
            map.put("tenantId", tenantId);
        }
        WxCarCmdLog carCmdLog = wxCarCmdLogService.getBySynId(map);
        if(carCmdLog != null) {
            logger.error("ETCP synId已入库： " + paramMap.toString());
            return true;
        }

        try {
            wxCarCmdLogService.saveOrUpdate(wxCarCmdLog);
        } catch (Exception e) {
            logger.error("etcpParkInCallback: 入库错误 " + e.getMessage() + "\n" + paramMap.toString());
            return true;
        }

        String phoneStrs = "";

        // 停车发券
        if (!StringUtils.isBlank(carNumber)) {
            // 根据车牌查找用户
            WxCUserCar userCarQ = new WxCUserCar();
            userCarQ.setTenantId(tenantId);
            userCarQ.setCarNumber(carNumber);
            userCarQ.setVendorType(EnumCarVendor.CAR_ETCP.getCode());
            // TODO 可能多用户关联同一张车牌
            List<WxCUserCar> userCarList = wxCUserCarService.getList(userCarQ);
            boolean bFirst = true;
            for (WxCUserCar userCar : userCarList) {
                wxCouponSendService.sendCouponToUser(EnumCouponSendSendType.CAR_STOP, userCar);
                WxCUser cUser = wxCUserService.getById(userCar.getCUserId());
                if(cUser != null){
                    if(bFirst) {
                        phoneStrs = cUser.getPhone();
                        bFirst = false;
                    } else {
                        phoneStrs += "," + cUser.getPhone();
                    }
                }
            }
        }

        try {
            // 保存WxCarPayRecord
            WxCarPayRecord record = new WxCarPayRecord();
            record.setVendorType(wxCarCmdLog.getVendorType());
            record.setSynId(synId);
            record.setParkId(parkId);
            record.setParkName(parkName);
            record.setUserType(userType);
            record.setPlateNumber(carNumber);
            if(StringUtils.isNotBlank(entranceTime)) {
                record.setEntranceTime(dateFormat.parse(entranceTime));
            }
            record.setFixParkingId(fixParkingId);
            record.setRemainingDays(remainingDays);
            record.setPhone(phoneStrs);
            record.setTenantId(tenantId);

            WxCarPayRecord query = new WxCarPayRecord();
            query.setSynId(synId);
            PageInfo<WxCarPayRecord> page = wxCarPayRecordService.findCarPayListByPage(query,1,1);
            if(page != null && CollectionUtils.isNotEmpty(page.getList())){
                record.setId(page.getList().get(0).getId());
            }
            wxCarPayRecordService.saveOrUpdate(record);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("WxCarPayRecord: 入库错误 ",e);
            logger.error("WxCarPayRecord: 入库错误 "+e.getMessage()+"," + paramMap.toString());
            return true;
        }
        return false;
    }

    private boolean doEtcpParkOut(@RequestBody Map<String, String> paramMap) {
        Date currentDate = new Date();

        WxCarCmdLog wxCarCmdLog = new WxCarCmdLog();
        wxCarCmdLog.setVendorType(EnumCarVendor.CAR_ETCP.getCode());
        wxCarCmdLog.setCmdType(EnumCarCmd.CAR_ETCP_CALLBACK_PARK_OUT.getCode());
        wxCarCmdLog.setCmdJson(JSON.toJSONString(paramMap));
        wxCarCmdLog.setCreateDate(currentDate);
        wxCarCmdLog.setUpdateDate(currentDate);

        String etcpParkId = paramMap.get(ETCPUtil.ETCP_PARK_ID);
        String tenantId = null;
        WxPark parkQ = new WxPark();
        parkQ.setVendorType(EnumCarVendor.CAR_ETCP.getCode());
        parkQ.setParkingId(etcpParkId);
        WxPark park = wxParkService.getByObj(parkQ);
        if (park == null) {
            logger.error("etcpParkOutCallback: ETCP车场未找到 " + etcpParkId);
            // return new Result(ErrorCode.CAR_PARK_NOT_FOUND.getCode(), "ETCP车场未找到"+ etcpParkId);
        } else {
            tenantId = park.getTenantId();
            wxCarCmdLog.setTenantId(tenantId);
        }

        try {
            wxCarCmdLogService.saveOrUpdate(wxCarCmdLog);
        } catch (Exception e) {
            logger.error("etcpParkOutCallback: 入库错误 " + e.getMessage() + "\n" + paramMap.toString());
            return true;
        }

        String synId = paramMap.get(ETCPUtil.ETCP_SYN_ID);
        String exitTime = paramMap.get(ETCPUtil.ETCP_EXIT_TIME);
        String stayedTime = paramMap.get(ETCPUtil.ETCP_STAYED_TIME);
        String carNumber = paramMap.get(ETCPUtil.ETCP_CAR_NUMBER);
        String parkId = paramMap.get(ETCPUtil.ETCP_PARK_ID);
        String parkName = paramMap.get(ETCPUtil.ETCP_PARK_NAME);
        String userType = paramMap.get(ETCPUtil.ETCP_USER_TYPE);
        String entranceTime = paramMap.get(ETCPUtil.ETCP_ENTRANCE_TIME);
        String fixParkingId = paramMap.get(ETCPUtil.ETCP_FIX_PARKING_ID);
        String remainingDays = paramMap.get(ETCPUtil.ETCP_REMAINING_DAYS);

        try {
            // 保存WxCarPayRecord
            WxCarPayRecord record = new WxCarPayRecord();
            record.setSynId(synId);
            if(StringUtils.isNotBlank(exitTime)) {
                record.setExitTime(dateFormat.parse(exitTime));
            }
            if(StringUtils.isNotBlank(stayedTime)) {
                record.setStayedTime(Long.parseLong(stayedTime));
            }
            record.setVendorType(wxCarCmdLog.getVendorType());
            record.setSynId(synId);
            record.setParkId(parkId);
            record.setParkName(parkName);
            record.setUserType(userType);
            record.setPlateNumber(carNumber);
            if(StringUtils.isNotBlank(entranceTime)) {
                record.setEntranceTime(dateFormat.parse(entranceTime));
            }
            record.setFixParkingId(fixParkingId);
            record.setRemainingDays(remainingDays);
            //record.setPhone(phoneStrs);
            record.setTenantId(tenantId);

            WxCarPayRecord query = new WxCarPayRecord();
            query.setSynId(synId);
            PageInfo<WxCarPayRecord> page = wxCarPayRecordService.findCarPayListByPage(query,1,1);
            if(page != null && CollectionUtils.isNotEmpty(page.getList())){
                record.setId(page.getList().get(0).getId());
            }
            wxCarPayRecordService.saveOrUpdate(record);
        } catch (Exception e) {
            logger.error("WxCarPayRecord: 出场更新错误 " +e.getMessage()+", " +paramMap.toString());
            return true;
        }
        return false;
    }
 }
