package com.liquidnet.service.slime.controller;

import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.liquidnet.commons.lang.constant.LnsRegex;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.commons.lang.util.ServletUtils;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.PagedResult;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinOrderTicketEntitiesVo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinPerformanceVo;
import com.liquidnet.service.slime.constant.SlimeAuthorizationConst;
import com.liquidnet.service.slime.dto.param.SlimeStationCheckOrderParam;
import com.liquidnet.service.slime.dto.param.SlimeStationUploadParam;
import com.liquidnet.service.slime.dto.vo.SlimeAuthorizationPerformanceVo;
import com.liquidnet.service.slime.dto.vo.SlimeStationCheckRefreshVo;
import com.liquidnet.service.slime.dto.vo.SlimeStationPerformanceVo;
import com.liquidnet.service.slime.service.impl.SlimeStationService;
import com.liquidnet.service.slime.util.ObjectUtil;
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.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
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.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@ApiSupport(order = 10099)
@Api(tags = "验票")
@Slf4j
@Validated
@RestController
@RequestMapping("station")
public class SlimeStationController {
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    SlimeStationService slimeStationService;

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

    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "演出列表")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "mod", value = "模块[recent-近期的,over-历史]", allowableValues = "recent,over"),
            @ApiImplicitParam(type = "form", required = false, dataType = "String", name = "match", value = "匹配字符[title|cityName|fieldName]"),
            @ApiImplicitParam(type = "form", required = true, dataType = "Integer", name = "pageNo", value = "页码", example = "1"),
            @ApiImplicitParam(type = "form", required = true, dataType = "Integer", name = "pageSize", value = "页记录数", example = "5"),
    })
    @GetMapping("performances")
    public ResponseDto<PagedResult<SlimeStationPerformanceVo>> performances(@Pattern(regexp = "\\b(recent|over)\\b", message = "模块参数无效")
                                                                               @RequestParam String mod,
                                                                            @RequestParam(required = false) String match,
                                                                            @RequestParam(defaultValue = "1", required = false) int pageNo,
                                                                            @RequestParam(defaultValue = "5", required = false) int pageSize) {
        PagedResult<SlimeStationPerformanceVo> pagedResult = ObjectUtil.getSlimeStationPerformanceVoPagedResult();
        List<SlimeStationPerformanceVo> voList = ObjectUtil.getSlimeStationPerformanceVoArrayList();
        String currentUid = CurrentUtil.getCurrentUid();
        long count = 0;
        try {
            // 查取当前用户下关联演出ID列表
            List<SlimeAuthorizationPerformanceVo> authorizationPerformanceVoList = slimeStationService.getCheckUserRelationVo(currentUid);
            if (!CollectionUtils.isEmpty(authorizationPerformanceVoList)) {
                if (log.isDebugEnabled()) {
                    log.debug("performanceRelationList:{}", JsonUtils.toJson(authorizationPerformanceVoList));
                }
                Map<String, SlimeAuthorizationPerformanceVo> authorizationPerformanceVoMap =
                        authorizationPerformanceVoList.stream().collect(Collectors.toMap(SlimeAuthorizationPerformanceVo::getPerformanceId, Function.identity()));
                Object[] performanceIdArr = authorizationPerformanceVoMap.keySet().toArray();


                Criteria criteria = Criteria.where("performancesId").in(performanceIdArr);
                LocalDateTime tmpDt = LocalDateTime.of(LocalDate.now(), LocalTime.of(0, 0, 0, 0));
                String tmpDtStr = DateUtil.format(tmpDt, DateUtil.Formatter.yyyyMMddHHmmss);
                switch (mod) {
                    case "recent":
                        log.debug(":::performances/recent:{},match:{}", currentUid, match);
                        criteria.andOperator(Criteria.where("timeEnd").gt(tmpDtStr));
                        break;
//                    case "down":
//                        log.info(":::performances/down:{}", currentUid);
//                        break;
                    case "over":
                        log.info(":::performances/over:{}", currentUid);
                        criteria.andOperator(Criteria.where("timeEnd").lte(tmpDtStr));
                        break;
                    default:
                        log.info(":::performances/default:{}", currentUid);
                        return ResponseDto.success(pagedResult);
                }
                if (StringUtils.isNotBlank(match)) {
                    java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("^.*" + match + ".*$", java.util.regex.Pattern.CASE_INSENSITIVE);
                    criteria.orOperator(
                            Criteria.where("title").regex(pattern), Criteria.where("cityName").regex(pattern), Criteria.where("fieldName").regex(pattern)
                    );
                }
                Query performancesVoQuery = Query.query(criteria);
                count = mongoTemplate.count(performancesVoQuery, KylinPerformanceVo.class.getSimpleName());
                if (count <= 0) return ResponseDto.success(pagedResult);

                performancesVoQuery.with(PageRequest.of(pageNo - 1, pageSize));
                performancesVoQuery.with(Sort.by(Sort.Order.asc("timeEnd"), Sort.Order.desc("sort")));
                voList = mongoTemplate.find(performancesVoQuery, SlimeStationPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
                if (log.isDebugEnabled()) {
                    log.debug("voList:{}", JsonUtils.toJson(voList));
                }

                // 包含`销售统计`权限的演出ID
                Object[] hasSalesPerformanceIdArr = authorizationPerformanceVoList.stream()
                        .filter(f -> f.getPermissionIds().contains(SlimeAuthorizationConst.PerformancePermission.SALES.getId()))
                        .map(SlimeAuthorizationPerformanceVo::getPerformanceId).toArray();
                SlimeAuthorizationPerformanceVo defaultAuthorizationPerformanceVo = SlimeAuthorizationPerformanceVo.getNew();
                if (ArrayUtils.isNotEmpty(hasSalesPerformanceIdArr)) {
                    // 查取演出对应的订单票明细
                    Query orderTicketEntitiesVoQuery = Query.query(Criteria.where("performanceId").in(hasSalesPerformanceIdArr).and("isPayment").is(1));
                    List<KylinOrderTicketEntitiesVo> oteVoList = mongoTemplate.find(orderTicketEntitiesVoQuery, KylinOrderTicketEntitiesVo.class, KylinOrderTicketEntitiesVo.class.getSimpleName());
                    if (log.isDebugEnabled()) {
                        log.debug("oteVoList:{}", JsonUtils.toJson(oteVoList));
                    }
                    // 转换订单票明细结构为Map<performanceId, List<KylinOrderTicketEntitiesVo>>
                    Map<String, List<KylinOrderTicketEntitiesVo>> oteVoMap = oteVoList.stream().collect(Collectors.groupingBy(KylinOrderTicketEntitiesVo::getPerformanceId));

                    for (SlimeStationPerformanceVo r : voList) {
                        List<String> permissionIds = authorizationPerformanceVoMap.getOrDefault(r.getPerformancesId(), defaultAuthorizationPerformanceVo).getPermissionIds();
                        r.setPermissionIds(StringUtils.join(permissionIds.toArray(), "."));

                        SlimeAuthorizationPerformanceVo authorizationPerformanceVo = authorizationPerformanceVoMap.get(r.getPerformancesId());
                        if (authorizationPerformanceVo.getPermissionIds().contains(SlimeAuthorizationConst.PerformancePermission.SALES.getId())) {
                            // 演出的所有订单票明细
                            List<KylinOrderTicketEntitiesVo> performanceTicketEntitiesVoList = oteVoMap.get(r.getPerformancesId());

                            if (!CollectionUtils.isEmpty(performanceTicketEntitiesVoList)) {
                                slimeStationService.salesStatisticsSetter(r, performanceTicketEntitiesVoList);
                            }
                        }
                        r.setTicketTimeList(null);
                    }
                } else {
                    voList.forEach(r -> {
                        List<String> permissionIds = authorizationPerformanceVoMap.getOrDefault(r.getPerformancesId(), defaultAuthorizationPerformanceVo).getPermissionIds();
                        r.setPermissionIds(StringUtils.join(permissionIds.toArray(), "."));
                        r.setTicketTimeList(null);
                    });
                }
            }
        } catch (Exception e) {
            log.error("验票:查取演出列表异常[station/performances]", e);
        }

        pagedResult.setList(voList).setTotal(count, pageSize).setPageSize(pageSize);
        return ResponseDto.success(pagedResult);
    }

    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "下载验票数据")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "performanceId", value = "演出ID[64]"),
    })
    @GetMapping("download")
    public ResponseDto<SlimeStationCheckRefreshVo> downloadTicketData(@NotBlank(message = "演出ID不能为空")
                                                                         @RequestParam String performanceId) {
        String currentUid = CurrentUtil.getCurrentUid();
        log.info("验票:下载验票数据[UID:{},performanceId:{}]", currentUid, performanceId);

        // 查取当前用户下关联演出ID列表
        List<SlimeAuthorizationPerformanceVo> authorizationPerformanceVoList = slimeStationService.getCheckUserRelationVo(currentUid);
        if (CollectionUtils.isEmpty(authorizationPerformanceVoList)) {
            return ResponseDto.failure(ErrorMapping.get("130901"));
        }
        List<SlimeAuthorizationPerformanceVo> targetAuthPerformanceVoList =
                authorizationPerformanceVoList.stream().filter(r -> r.getPerformanceId().equals(performanceId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(targetAuthPerformanceVoList)) {
            return ResponseDto.failure(ErrorMapping.get("130902"));
        }
        SlimeAuthorizationPerformanceVo authorizationPerformanceVo = targetAuthPerformanceVoList.get(0);
//        LocalDateTime canDownDt = DateUtil.Formatter.yyyyMMddHHmmss.parse(relationParam.getCanDownTime());
//        if (canDownDt.isAfter(LocalDateTime.now())) {
//            return ResponseDto.failure(ErrorMapping.get("130903"));
//        }

        return ResponseDto.success(slimeStationService.downloadRefreshTicketData(authorizationPerformanceVo, performanceId, null));
    }

    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "刷新验票数据")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "performanceId", value = "演出ID[64]"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "latestUpdateAt", value = "最近更新时间[yyyy-MM-dd HH:mm:ss]"),
    })
    @PostMapping("refresh")
    public ResponseDto<SlimeStationCheckRefreshVo> refreshTicketData(@NotBlank(message = "演出ID不能为空")
                                                                        @RequestParam String performanceId,
                                                                     @Pattern(regexp = LnsRegex.Valid.DATETIME_FULL, message = "时间格式有误")
                                                                        @RequestParam String latestUpdateAt) {
        String currentUid = CurrentUtil.getCurrentUid();
        log.info("验票:刷新验票数据[UID:{},performanceId:{},latestUpdateAt:{}]", currentUid, performanceId, latestUpdateAt);

        // 查取当前用户下关联演出ID列表
        List<SlimeAuthorizationPerformanceVo> authorizationPerformanceVoList = slimeStationService.getCheckUserRelationVo(currentUid);
        if (CollectionUtils.isEmpty(authorizationPerformanceVoList)) {
            return ResponseDto.failure(ErrorMapping.get("130901"));
        }
        List<SlimeAuthorizationPerformanceVo> targetAuthPerformanceVoList =
                authorizationPerformanceVoList.stream().filter(r -> r.getPerformanceId().equals(performanceId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(targetAuthPerformanceVoList)) {
            return ResponseDto.failure(ErrorMapping.get("130902"));
        }
        SlimeAuthorizationPerformanceVo authorizationPerformanceVo = targetAuthPerformanceVoList.get(0);
//        LocalDateTime canDownDt = DateUtil.Formatter.yyyyMMddHHmmss.parse(relationParam.getCanDownTime());
//        if (canDownDt.isAfter(LocalDateTime.now())) {
//            return ResponseDto.failure(ErrorMapping.get("130903"));
//        }

        return ResponseDto.success(slimeStationService.downloadRefreshTicketData(authorizationPerformanceVo, performanceId, latestUpdateAt));
    }

    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "上载验票数据")
    @PutMapping("upload")
    public ResponseDto<Object> uploadTicketData(@Valid @RequestBody SlimeStationUploadParam parameter) {
        String currentUid = CurrentUtil.getCurrentUid();
        log.info("验票:上载验票数据[UID:{}]", currentUid);

        HttpServletRequest request = ServletUtils.getRequest();
        String agent = request.getParameter("User-Agent");
        if (StringUtils.containsIgnoreCase(agent, "android")) {
            parameter.setCheckClient("ANDROID");
        } else if (StringUtils.containsIgnoreCase(agent, "iPhone")
                || StringUtils.containsIgnoreCase(agent, "iPod")
                || StringUtils.containsIgnoreCase(agent, "iPad")) {
            parameter.setCheckClient("IOS");
        } else {
            parameter.setCheckClient("APP");
        }

        List<SlimeStationCheckOrderParam> checkOrderParamList = parameter.getCheckOrderParamList();
        if (!CollectionUtils.isEmpty(checkOrderParamList)) {
            slimeStationService.updateByStation(parameter);
        }

        return ResponseDto.success();
    }

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

//    private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
//        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
//        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
//    }

    /* ------------------------------------------------------------------ */
}
