package com.liquidnet.service.kylin.controller;

import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.core.JwtValidator;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.HttpUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.kylin.dto.param.CheckPerformanceRelationParam;
import com.liquidnet.service.kylin.dto.param.KylinStationCheckOrderParam;
import com.liquidnet.service.kylin.dto.vo.*;
import com.liquidnet.service.kylin.service.partner.IKylinCheckUserPartnerService;
import com.liquidnet.service.kylin.service.partner.IKylinCheckUserPerformancesPartnerService;
import com.liquidnet.service.kylin.utils.DataUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Api(tags = "验票")
@Slf4j
@RestController
@RequestMapping("station")
public class KylinStationController {
    @Autowired
    Environment environment;
    @Autowired
    JwtValidator jwtValidator;
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    DataUtils dataUtils;

    @ApiOperation(value = "手机号密码登录")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", dataType = "String", name = "mobile", value = "手机号"),
            @ApiImplicitParam(type = "form", dataType = "String", name = "passwd", value = "密码"),
    })
    @PostMapping("login")
    public ResponseDto<String> login(@RequestParam String mobile, @RequestParam String passwd) {
        log.info("mobile:{},passwd:{}", mobile, passwd);

        return this.loginVerification(mobile, passwd, true);
    }

    @ApiOperation(value = "手机号验证码登录")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "body", required = true, dataType = "String", name = "mobile", value = "手机号"),
            @ApiImplicitParam(type = "body", required = true, dataType = "String", name = "code", value = "验证码"),
    })
    @PostMapping("login/sms")
    public ResponseDto<String> loginBySms(@RequestParam String mobile, @RequestParam String code) {
        log.info("mobile:{},code:{}", mobile, code);

        return this.loginVerification(mobile, code, false);
    }

    @ApiOperation(value = "登出")
    @PostMapping("out")
    public ResponseDto<String> out() {
        String checkUserId = CurrentUtil.getCurrentUid();

        String token = CurrentUtil.getToken();

        String ssoKeyUidM5Token = jwtValidator.getSsoRedisKey().concat(CurrentUtil.getCurrentUid()).concat(
                DigestUtils.md5DigestAsHex(token.getBytes(StandardCharsets.UTF_8))
        );

        log.info("###logout:checkUserId:{}\nssoKey:{}\ntoken:{}", checkUserId, ssoKeyUidM5Token, token);

        redisUtil.set(ssoKeyUidM5Token, false);

        return ResponseDto.success();
    }

    /* ------------------------------------------------------------------ */

    @ApiOperation(value = "演出列表")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "body", required = true, dataType = "String", name = "mod", value = "模块[recent-近期的,down-已下载,over-历史]", allowableValues = "recent,down,over"),
    })
    @GetMapping("performances/{mod}")
    public ResponseDto<List<KylinStationPerformanceVo>> performances(@PathVariable String mod) {
        List<KylinStationPerformanceVo> voList = new ArrayList<>();
        log.info("mod:{}", mod);

        switch (mod) {
            case "recent":
                KylinCheckUserPerformanceVo checkUserRelationVo = dataUtils.getCheckUserRelationVo(CurrentUtil.getCurrentUid());

                if (null != checkUserRelationVo) {
                    List<CheckPerformanceRelationParam> relationParams = checkUserRelationVo.getRelationParams();

                    if (!CollectionUtils.isEmpty(relationParams)) {

                        relationParams.forEach(r -> {
                            KylinPerformanceVo performanceVo = dataUtils.getPerformanceVo(r.getPerformanceId());

                            KylinStationPerformanceVo vo = KylinStationPerformanceVo.getNew().copy(performanceVo);

                            vo.setCanDownTime(r.getCanDownTime());

                            // TODO: 2021/5/30 票种数据统计
                            KylinStationTicketVo ticketVo = KylinStationTicketVo.getNew();
                            ticketVo.setTicketsId("1");
                            ticketVo.setType("1");
                            ticketVo.setTitle("测试数据");
                            ticketVo.setPrice(BigDecimal.TEN);
                            ticketVo.setUseStart("2021-05-30");
                            ticketVo.setUseEnd("2021-06-02");
                            ticketVo.setNumber(100);
                            ticketVo.setPriceSum(ticketVo.getPrice().multiply(BigDecimal.valueOf(ticketVo.getNumber())));
                            ticketVo.setCheckedNum(0);
                            ticketVo.setRemainderNum(ticketVo.getNumber() - ticketVo.getCheckedNum());

                            vo.setTicketVoList(Arrays.asList(ticketVo, ticketVo));

                            voList.add(vo);
                        });
                    }
                }
                break;
            case "down":

                break;
            case "over":

                break;
            default:
                break;
        }
        return ResponseDto.success(voList);
    }

    @ApiOperation(value = "下载验票数据")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "body", required = true, dataType = "String", name = "type", value = "类型[101-音乐节,102小型演出(livehouse演出),103巡演]", allowableValues = "101,102,103"),
            @ApiImplicitParam(type = "body", required = true, dataType = "String", name = "performanceId", value = "演出ID[64]"),
    })
    @GetMapping("download/{type}/{performanceId}")
    public ResponseDto<List<KylinStationCheckOrderVo>> downloadTicketData(@PathVariable String type, @PathVariable String performanceId) {
        log.info("type:{},performanceId:{}", type, performanceId);



        return ResponseDto.success(Collections.singletonList(KylinStationCheckOrderVo.getNew()));
    }

    @ApiOperation(value = "上载验票数据")
    @PostMapping("upload")
    public ResponseDto<Boolean> uploadTicketData(@RequestBody List<KylinStationCheckOrderParam> checkDataParams) {
        log.info("checkDataParams:{}", JsonUtils.toJson(checkDataParams));



        return ResponseDto.success(true);
    }

    /* ------------------------------------------------------------------ */

    private ResponseDto<String> loginVerification(String mobile, String identity, boolean isPasswd) {
        KylinCheckUserVo checkUserVo = mongoTemplate.findOne(Query.query(Criteria.where("mobile").is(mobile)),
                KylinCheckUserVo.class, KylinCheckUserVo.class.getSimpleName());

        if (null == checkUserVo) {
            return ResponseDto.failure(ErrorMapping.get("20601"));
        }

        if (isPasswd) {// 校验密码
            if (checkUserVo.getPwd().equals(DigestUtils.md5DigestAsHex(identity.getBytes()))) {
                return this.loginAuthentication(checkUserVo);
            }
            return ResponseDto.failure(ErrorMapping.get("20602"));
        } else {// 校验验证码
            if (Arrays.asList("dev", "test").contains(environment.getProperty("spring.profiles.active"))) {
                if ("111111".equals(identity)) {
                    return this.loginAuthentication(checkUserVo);
                }
                return ResponseDto.failure(ErrorMapping.get("20002"));
            }

            try {
                LinkedMultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
                paramsMap.add("mobile", mobile);
                paramsMap.add("code", identity);
                LinkedMultiValueMap<String, String> headersMap = new LinkedMultiValueMap<>();
                headersMap.add("token", null);

                // TODO: 2021/5/12
                String respStr = HttpUtil.get("https://service.zhengzai.tv/smsValidation", paramsMap, headersMap);
                log.info("###PHP.API.RESP:{}", respStr);

                Map respMap = JsonUtils.fromJson(respStr, Map.class);

                if (StringUtils.equalsIgnoreCase("OK", (String) respMap.get("message"))) {
                    return this.loginAuthentication(checkUserVo);
                }
                return ResponseDto.failure(ErrorMapping.get("20002"));
            } catch (Exception e) {
                log.error("验证码验证异常[mobile:{},code:{}]", mobile, identity, e);
                return ResponseDto.failure(ErrorMapping.get("20002"));
            }
        }
    }

    private ResponseDto<String> loginAuthentication(KylinCheckUserVo checkUserVo) {
        String uid = checkUserVo.getCheckUserId();

        String ssoKeyUid = jwtValidator.getSsoRedisKey().concat(uid);

        Map<String, Object> claimsMap = new HashMap<>();
        claimsMap.put("uid", uid);
        claimsMap.put("mobile", checkUserVo.getMobile());
        claimsMap.put("nickname", checkUserVo.getName());

        String token = jwtValidator.create(claimsMap);

        String ssoKeyUidM5Token = ssoKeyUid.concat(DigestUtils.md5DigestAsHex(token.getBytes(StandardCharsets.UTF_8)));

        redisUtil.set(ssoKeyUidM5Token, true, jwtValidator.getExpireTtl() * 60);

        return ResponseDto.success(token);
    }
}
