package com.xiang.xservice.application.script.fwd.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.xiang.xmc.service.http.helper.HttpRequestHelper;
import com.xiang.xservice.application.script.fwd.constants.PriceRange;
import com.xiang.xservice.application.script.fwd.entity.pojo.FPerformConfig;
import com.xiang.xservice.application.script.fwd.entity.pojo.FPerformProjectInfo;
import com.xiang.xservice.application.script.fwd.entity.pojo.FPerformSeatInfo;
import com.xiang.xservice.application.script.fwd.entity.pojo.FUserConfig;
import com.xiang.xservice.application.script.fwd.entity.req.ProjectOrderCreateReq;
import com.xiang.xservice.application.script.fwd.entity.resp.http.perform.ProjectOrderCreateResp;
import com.xiang.xservice.application.script.fwd.mapper.FwdPerformConfigMapper;
import com.xiang.xservice.application.script.fwd.mapper.FwdPerformProjectInfoMapper;
import com.xiang.xservice.application.script.fwd.mapper.FwdPerformSeatInfoMapper;
import com.xiang.xservice.application.script.fwd.mapper.FwdUserConfigMapper;
import com.xiang.xservice.application.script.fwd.service.DingTalkScriptFWDService;
import com.xiang.xservice.application.script.fwd.service.IPerformService;
import com.xiang.xservice.application.script.fwd.service.IPerformServiceHttp;
import com.xiang.xservice.basic.config.MyThreadFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.logging.log4j.util.Strings;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Author: xiang
 * @Date: 2025-07-25 15:16
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PerformServiceImpl implements IPerformService {

    private final FwdPerformSeatInfoMapper fwdPerformSeatInfoMapper;
    private final FwdPerformProjectInfoMapper fwdPerformProjectInfoMapper;
    private final FwdPerformConfigMapper fwdPerformConfigMapper;
    private final IPerformServiceHttp performServiceHttp;
    private final DingTalkScriptFWDService dingTalkService;
    private final FwdUserConfigMapper fwdUserConfigMapper;
    private final HttpRequestHelper httpRequestHelper;
    private final ExecutorService es =
            new ThreadPoolExecutor(
                    10,
                    20,
                    1000,
                    TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(),
                    new MyThreadFactory("ticket-", Boolean.TRUE),
                    new ThreadPoolExecutor.AbortPolicy());

    @Override
    public FPerformProjectInfo getPerformByProjectId(Long projectId) {
        return fwdPerformProjectInfoMapper.getProjectByProjectId(projectId);
    }

    @Override
    public List<FPerformSeatInfo> getPerformSeatInfoByProjectId(Long projectId) {
        return fwdPerformSeatInfoMapper.getPerformSeatByProjectId(projectId);
    }

    @Override
    public Boolean createProjectOrder(Long projectId, List<Long> frequentIds, String token) throws Exception {
        FPerformProjectInfo performByProjectId = getPerformByProjectId(projectId);
        if (Objects.isNull(performByProjectId)) {
            log.info("该projectId:{}暂无演出信息", projectId);
            return Boolean.FALSE;
        }
        List<FPerformSeatInfo> seatInfoByProjectId = getPerformSeatInfoByProjectId(projectId);
        if (CollectionUtils.isEmpty(seatInfoByProjectId)) {
            log.info("该projectId:{}暂无座位信息", projectId);
            return Boolean.FALSE;
        }
        Map<Long, List<FPerformSeatInfo>> performMap = seatInfoByProjectId.stream().filter(item -> 0 == item.getSoldOut()).collect(Collectors.groupingBy(FPerformSeatInfo::getPerformId));
        // todo 场次座位排序 优先 场次先后顺序 周六>周日>周五>工作日 根据场次分组进行
        // todo 座位价格排序 优先 600-900 > 900-1300 > 1300-1600 > 1600~* > 0-600
        for (Long performId : performMap.keySet()) {
            List<FPerformSeatInfo> fPerformSeatInfos = performMap.get(performId);
            AtomicReference<BigDecimal> atomicPrice = new AtomicReference<>();
            fPerformSeatInfos.stream().map(FPerformSeatInfo::getPrice).max(BigDecimal::compareTo).ifPresent(atomicPrice::set);
            BigDecimal price = atomicPrice.get();
            // 排序座位
            /*
                0: 600-900
                1: 900-1300
                2: 1300-1600
                3: >1600
                4: <=600
            */
            List<Long> seatIds = fPerformSeatInfos.stream()
                    .collect(Collectors.groupingBy(
                            seat -> PriceRange.fromPrice(seat.getPrice()),
                            Collectors.collectingAndThen(Collectors.toList(), list -> {
                                Collections.shuffle(list);
                                return list;
                            })
                    ))
                    .entrySet().stream()
                    .sorted(Comparator.comparing(entry -> entry.getKey().getIndex()))
                    .flatMap(entry -> entry.getValue().stream())
                    .map(FPerformSeatInfo::getSeatPlanId)
                    .collect(Collectors.toList());
            ProjectOrderCreateReq projectOrderCreateReq = buildReqV2(projectId, frequentIds, seatIds, performId, price);
            for (int i = 1; i <= 100; i++) {
                ProjectOrderCreateResp projectOrder = httpRequestHelper.fetchWithRetry(() -> performServiceHttp.createProjectOrder(projectOrderCreateReq, token), "create-project-order");
                if (Objects.nonNull(projectOrder)) {
                    log.info("下单成功，订单信息:{}", JSONObject.toJSONString(projectOrder));
                    String msg = "【芬玩岛】下单成功✅✅✅，演出名称：" + performByProjectId.getProjectName() + "，请在5分钟内完成付款！订单号：" + projectOrder.getOrderNo();
                    dingTalkService.sendScriptMsg(msg);
                    return Boolean.TRUE;
                }
            }
        }
        dingTalkService.sendScriptMsg("【芬玩岛】下单失败❌❌❌，演出名称：" + performByProjectId.getProjectName());
        return Boolean.FALSE;
    }

    @NotNull
    private static ProjectOrderCreateReq buildReqV2(Long projectId, List<Long> frequentIds, List<Long> seatPlanIds, Long perfomrId, BigDecimal price) {
        ProjectOrderCreateReq projectOrderCreateReq = new ProjectOrderCreateReq();
        projectOrderCreateReq.setDeliveryType(1);
        projectOrderCreateReq.setContactName("朱吉祥");
        projectOrderCreateReq.setContactPhone("15858717571");
        projectOrderCreateReq.setPayment(price.multiply(BigDecimal.valueOf(frequentIds.size())).setScale(2));
        projectOrderCreateReq.setTotalPrice(price.multiply(BigDecimal.valueOf(frequentIds.size())).setScale(2, BigDecimal.ROUND_HALF_UP));
        projectOrderCreateReq.setPerformId(perfomrId);
        projectOrderCreateReq.setProjectId(projectId.toString());
        projectOrderCreateReq.setPrivilegeCodeList(new ArrayList<>());
        projectOrderCreateReq.setAudienceCount(frequentIds.size());
        projectOrderCreateReq.setFrequentIds(frequentIds);
        projectOrderCreateReq.setSeatPlanIds(seatPlanIds);
        projectOrderCreateReq.setBlackBox(":0");
        projectOrderCreateReq.setCombineTicketVos(null);
        projectOrderCreateReq.setOrdinaryTicketVos(null);
        projectOrderCreateReq.setActivityId(Strings.EMPTY);
        projectOrderCreateReq.setActivityType(0);
        return projectOrderCreateReq;
    }

    @Override
    public List<FPerformConfig> getAvailablePerform() {
        return fwdPerformConfigMapper.getAvailablePerform();
    }

    @Override
    public Boolean updateProjectInfo(FPerformProjectInfo projectInfo) {
        return fwdPerformProjectInfoMapper.update(projectInfo) > 0;
    }

    @Override
    public FPerformSeatInfo getSeatInfoBySeatId(Long seatId) {
        return fwdPerformSeatInfoMapper.getBySeatPlanId(seatId);
    }

    @Override
    public Boolean updateSeatInfo(FPerformSeatInfo seatInfoBySeatId) {
        return fwdPerformSeatInfoMapper.update(seatInfoBySeatId) > 0;
    }

    @Override
    public Boolean addSeatInfo(FPerformSeatInfo fPerformSeatInfo) {
        return fwdPerformSeatInfoMapper.batchSave(Collections.singletonList(fPerformSeatInfo)) > 0;
    }

    @Override
    public Boolean updateTokenByName(String name, String token) {
        FUserConfig userByName = fwdUserConfigMapper.getUserByName(name);
        if (Objects.isNull(userByName)) {
            FUserConfig fUserConfig = new FUserConfig();
            fUserConfig.setName(name);
            fUserConfig.setToken(token);
            fUserConfig.setStatus(1);
            return fwdUserConfigMapper.insert(fUserConfig) > 0;
        } else {
            return fwdUserConfigMapper.updateTokenByName(name, token) > 0;
        }
    }
}
