package com.xiang.xservice.application.script.fwd.schedule;

import com.google.common.collect.Lists;
import com.xiang.xmc.service.http.helper.HttpRequestHelper;
import com.xiang.xservice.application.script.fwd.entity.pojo.FAudienceConfig;
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.resp.http.audience.AudienceMemberInfo;
import com.xiang.xservice.application.script.fwd.entity.resp.http.perform.Perform;
import com.xiang.xservice.application.script.fwd.entity.resp.http.perform.PerformDetail;
import com.xiang.xservice.application.script.fwd.entity.resp.http.perform.PerformInfo;
import com.xiang.xservice.application.script.fwd.entity.resp.http.perform.ProjectInfoResp;
import com.xiang.xservice.application.script.fwd.entity.resp.http.perform.ProjectList;
import com.xiang.xservice.application.script.fwd.entity.resp.http.perform.ProjectsResp;
import com.xiang.xservice.application.script.fwd.entity.resp.http.perform.SeatPlan;
import com.xiang.xservice.application.script.fwd.entity.resp.http.perform.SeatPlanStatus;
import com.xiang.xservice.application.script.fwd.mapper.FwdAudienceConfigMapper;
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.IPerformServiceHttp;
import com.xiang.xservice.basic.common.req.BaseRequest;
import com.xiang.xservice.basic.config.MyThreadFactory;
import com.xiang.xservice.basic.utils.DateUtils;
import com.xiang.xservice.basic.utils.RandomCodeUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

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.function.Function;
import java.util.stream.Collectors;

/**
 * 芬玩岛拉取数据定时任务
 *
 * @Author: xiang
 * @Date: 2025-07-24 17:19
 */
@Component
@RequiredArgsConstructor
@Slf4j
@RestController
public class PullDataFromFWDJob {

    private final IPerformServiceHttp performServiceHttp;
    private final FwdPerformProjectInfoMapper performProjectInfoMapper;
    private final FwdPerformConfigMapper performConfigMapper;
    private final FwdPerformSeatInfoMapper performSeatInfoMapper;
    private final FwdUserConfigMapper userConfigMapper;
    private final FwdAudienceConfigMapper audienceConfigMapper;
    private final HttpRequestHelper httpRequestHelper;

    private final ExecutorService es =
            new ThreadPoolExecutor(
                    1,
                    1,
                    1000,
                    TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(),
                    new MyThreadFactory("fwd-pull-data-http", Boolean.TRUE),
                    new ThreadPoolExecutor.AbortPolicy());

    private FPerformProjectInfo saveProjectInfo(ProjectList project, ProjectInfoResp projectInfoFromHttp) {
        FPerformProjectInfo fPerformProjectInfo = new FPerformProjectInfo();
        fPerformProjectInfo.setNameDisplay(projectInfoFromHttp.getNameDisplay());
        fPerformProjectInfo.setStatus(projectInfoFromHttp.getStatus());
        fPerformProjectInfo.setProjectSource(projectInfoFromHttp.getProjectSource());
        fPerformProjectInfo.setIsHasSeat(projectInfoFromHttp.getIsHasSeat());
        fPerformProjectInfo.setIsChoiceSeat(projectInfoFromHttp.getIsChoiceSeat());
        fPerformProjectInfo.setHighestPrice(projectInfoFromHttp.getHighPrice());
        if (StringUtils.isNotBlank(projectInfoFromHttp.getProjectStartDate())) {
            fPerformProjectInfo.setProjectStartDate(DateUtils.getDateFromStr(projectInfoFromHttp.getProjectStartDate(), "yyyy/MM/dd"));
        }
        if (StringUtils.isNotBlank(projectInfoFromHttp.getProjectEndDate())) {
            fPerformProjectInfo.setProjectEndDate(DateUtils.getDateFromStr(projectInfoFromHttp.getProjectEndDate(), "yyyy/MM/dd"));
        }
        fPerformProjectInfo.setSubClassifyName(projectInfoFromHttp.getSubClassifyName());

        fPerformProjectInfo.setProjectName(project.getName());
        fPerformProjectInfo.setBizId(project.getBizId());
        fPerformProjectInfo.setProjectId(project.getProjectId());
        fPerformProjectInfo.setTagName(project.getTagName());
        fPerformProjectInfo.setTagRemark(project.getTagRemark());
        fPerformProjectInfo.setProjectCity(project.getCity());
        fPerformProjectInfo.setShortCity(project.getShortCity());
        fPerformProjectInfo.setVenueName(project.getVenueName());
        fPerformProjectInfo.setLowestPrice(project.getLowestPrice());
        if (StringUtils.isNotBlank(projectInfoFromHttp.getPreSaleTime())) {
            fPerformProjectInfo.setPreSaleTime(DateUtils.getDateTimeFromStr(projectInfoFromHttp.getPreSaleTime(), "yyyy/MM/dd HH:mm:ss"));
        }
        performProjectInfoMapper.insert(fPerformProjectInfo);
        return fPerformProjectInfo;
    }

    /**
     * 每月拉取观影人数据更新
     */
    @Scheduled(cron = "0 0 0 1 1/1 ? ")
    public void pullAudienceMemberInfo() {
        List<FUserConfig> availableUser = userConfigMapper.getAvailableUser();
        if (CollectionUtils.isEmpty(availableUser)) {
            return;
        }
        availableUser.forEach(user -> {
            List<AudienceMemberInfo> audienceMemberInfo = performServiceHttp.getAudienceMemberInfo(user.getToken());
            if (CollectionUtils.isNotEmpty(audienceMemberInfo)) {
                List<FAudienceConfig> list = audienceMemberInfo.stream().map(audience -> {
                    FAudienceConfig info = new FAudienceConfig();
                    info.setDelFlag(0);
                    info.setFrequentId(audience.getFrequentContactsId());
                    info.setFrequentNo(audience.getIdCard());
                    info.setFrequentName(audience.getName());
                    info.setStatus(1);
                    info.setFrequentPhone(audience.getPhone());
                    info.setUserId(user.getId());
                    return info;
                }).collect(Collectors.toList());
                audienceConfigMapper.delByUserId(user.getId());
                audienceConfigMapper.batchSave(list);
            }
        });
    }

    @PostMapping("/pullPerformDataJob")
    @Scheduled(cron = "0 0 1 1/1 * ?")
    public void pullPerformDataJobV2() {
        int pageNum = 0;
        List<FUserConfig> availableUser = userConfigMapper.getAvailableUser();
        String token = availableUser.get(0).getToken();
        while (true) {
            pageNum++;
            BaseRequest baseRequest = new BaseRequest();
            baseRequest.setCurrent(pageNum);
            baseRequest.setPageSize(50);
            ProjectsResp projectsResp = httpRequestHelper.fetchWithRetry(() -> performServiceHttp.getShowProjectsFromHttp(baseRequest), "fetch-projects");
            if (Objects.isNull(projectsResp) || CollectionUtils.isEmpty(projectsResp.getList())) {
                break;
            }
            List<ProjectList> projects = projectsResp.getList();
            List<FPerformProjectInfo> results = Lists.newArrayList();
            for (ProjectList project : projects) {
                FPerformProjectInfo performProjectInfo = handleProjectData(project, token);
                results.add(performProjectInfo);
            }
            results = results.stream().filter(Objects::nonNull).toList();
            // 查询演出座位档次信息
            List<FPerformSeatInfo> insertList = Lists.newCopyOnWriteArrayList();
            List<FPerformSeatInfo> updateList = Lists.newCopyOnWriteArrayList();
            for (FPerformProjectInfo result : results) {
                List<SeatPlan> seatPlans = result.getSeatPlans();
                if (CollectionUtils.isEmpty(seatPlans)) {
                    continue;
                }
                List<Long> seatPlanIds = seatPlans.stream().map(SeatPlan::getSeatPlanId).toList();
                List<SeatPlanStatus> seatPlanStatusList = httpRequestHelper.fetchWithRetry(() -> performServiceHttp.getSeatPlanStatusFromHttp(seatPlanIds, token), "fetch-seat-plan-status");
                if (CollectionUtils.isEmpty(seatPlanStatusList)) {
                    continue;
                }
                Map<Long, SeatPlanStatus> map = seatPlanStatusList.stream().collect(Collectors.toMap(SeatPlanStatus::getSeatPlanId, Function.identity(), (a, b) -> a));
                Map<Long, FPerformSeatInfo> existSeatMap = performSeatInfoMapper.getPerformSeatInfoBySeatIds(seatPlanIds)
                        .stream()
                        .collect(Collectors.toMap(FPerformSeatInfo::getSeatPlanId, Function.identity(), (a, b) -> a));
                for (SeatPlan seatPlan : seatPlans) {
                    if (map.containsKey(seatPlan.getSeatPlanId())) {
                        SeatPlanStatus value = map.get(seatPlan.getSeatPlanId());
                        if (existSeatMap.containsKey(seatPlan.getSeatPlanId())) {
                            // 更新
                            FPerformSeatInfo performSeatInfo = existSeatMap.get(seatPlan.getSeatPlanId());
                            performSeatInfo.setSoldStock(value.getSoldOutFlag() ? 1 : 0);
                            updateList.add(performSeatInfo);
                        } else {
                            // 新增
                            saveSeatInfo(result.getProjectId(), seatPlan.getSeatPlanId(), value, seatPlan, insertList);
                        }
                    }
                }
                stopThread();
            }
            if (!CollectionUtils.isEmpty(insertList)) {
                performSeatInfoMapper.batchSave(insertList);
            }
            if (!CollectionUtils.isEmpty(updateList)) {
                for (FPerformSeatInfo seatInfo : updateList) {
                    performSeatInfoMapper.update(seatInfo);
                }
            }
        }
    }

    private FPerformProjectInfo handleProjectData(ProjectList project, String token) {
        // 查询演出的详情
        ProjectInfoResp projectInfoFromHttp = httpRequestHelper.fetchWithRetry(() -> performServiceHttp.getProjectInfoFromHttp(project.getProjectId(), token), "fetch-project-info");
        if (Objects.isNull(projectInfoFromHttp)) {
            return null;
        }
        // 查询演出信息
        Perform performsByProjectIdFromHttp = httpRequestHelper.fetchWithRetry(() -> performServiceHttp.getPerformsByProjectIdFromHttp(project.getProjectId(), token), "fetch-perform-by-project-id");
        if (Objects.isNull(performsByProjectIdFromHttp)) {
            return null;
        }
        // 查询数据库
        FPerformProjectInfo projectInfo = performProjectInfoMapper.getProjectByProjectId(performsByProjectIdFromHttp.getProjectId());
        if (Objects.isNull(projectInfo)) {
            // 不存在则新增
            projectInfo = saveProjectInfo(project, projectInfoFromHttp);
        } else {
            // 存在则更新
            buildUpdateProjectInfo(project, projectInfo, projectInfoFromHttp);
            performProjectInfoMapper.update(projectInfo);
        }
        List<PerformInfo> performInfos = performsByProjectIdFromHttp.getPerformInfos();
        List<SeatPlan> seats = Lists.newArrayList();
        if (CollectionUtils.isEmpty(performInfos)) {
            return projectInfo;
        }
        for (PerformInfo performInfo : performInfos) {
            List<PerformDetail> info = performInfo.getPerformInfo();
            if (CollectionUtils.isEmpty(info)) {
                return projectInfo;
            }
            for (PerformDetail performDetail : info) {
                seats.addAll(performDetail.getSeatPlans().stream().toList());
            }

        }
        projectInfo.setSeatPlans(seats);
        stopThread();
        return projectInfo;
    }

    private static void stopThread() {
        try {
            String random = RandomCodeUtils.getNumberRandomCode(1);
            log.info("线程暂停:{}s", random);
            Thread.sleep(Long.parseLong(random) * 1000);
        } catch (InterruptedException e) {
            log.error("线程暂停1s失败");
        }
    }

    private static void saveSeatInfo(Long projectId, Long seatPlanId, SeatPlanStatus seatPlanStatus, SeatPlan seatPlan, List<FPerformSeatInfo> insertList) {
        FPerformSeatInfo fPerformSeatInfo = new FPerformSeatInfo();
        fPerformSeatInfo.setSeatPlanId(seatPlanId);
        fPerformSeatInfo.setSeatPlanName(seatPlan.getSeatPlanName());
        fPerformSeatInfo.setPerformId(seatPlan.getPerformId());
        fPerformSeatInfo.setPerformName(seatPlan.getPerformName());
        fPerformSeatInfo.setStopSale(seatPlan.getStopSale());
        fPerformSeatInfo.setShelfStatus(seatPlan.getShelfStatus());
        fPerformSeatInfo.setPrice(seatPlan.getPrice());
        fPerformSeatInfo.setDiscountPrice(seatPlan.getDiscountPrice());
        fPerformSeatInfo.setSubStatus(seatPlan.getSubStatus());
        fPerformSeatInfo.setQuantity(seatPlan.getQuantity());
        fPerformSeatInfo.setStatus(seatPlan.getStatus());
        fPerformSeatInfo.setMaxSellStock(seatPlan.getMaxSellStock());
        fPerformSeatInfo.setSoldStock(seatPlan.getSoldStock());
        fPerformSeatInfo.setLeftStock(seatPlan.getLeftStock());
        fPerformSeatInfo.setAbleSaleQuantity(seatPlan.getAbleSaleQuantity());
        fPerformSeatInfo.setAshShow(seatPlan.getAshShow());
        fPerformSeatInfo.setAshShowDesc(seatPlan.getAshShowDesc());
        fPerformSeatInfo.setSelectable(seatPlan.getSelectable());
        fPerformSeatInfo.setDisplay(seatPlan.getDisplay());
        fPerformSeatInfo.setAvailableTicketQuantity(seatPlan.getAvailableTicketQuantity());
        fPerformSeatInfo.setAvailableAllTicketQuantity(seatPlan.getAvailableAllTicketQuantity());
        if (StringUtils.isNotBlank(seatPlan.getSaleTime())) {
            fPerformSeatInfo.setSaleTime(DateUtils.getDateTimeFromStr(seatPlan.getSaleTime()));
        }
        fPerformSeatInfo.setProjectId(projectId);
        if (!seatPlanStatus.getSoldOutFlag() && seatPlanStatus.getStandbyStatus().equals(10)) {
            fPerformSeatInfo.setSoldOut(0);
        } else {
            fPerformSeatInfo.setSoldOut(1);
        }
        insertList.add(fPerformSeatInfo);
    }

    private static void buildUpdateProjectInfo(ProjectList projectList, FPerformProjectInfo projectInfo, ProjectInfoResp projectInfoFromHttp) {
        projectInfo.setNameDisplay(projectInfoFromHttp.getNameDisplay());
        projectInfo.setStatus(projectInfoFromHttp.getStatus());
        projectInfo.setProjectSource(projectInfoFromHttp.getProjectSource());
        projectInfo.setIsHasSeat(projectInfoFromHttp.getIsHasSeat());
        projectInfo.setIsChoiceSeat(projectInfoFromHttp.getIsChoiceSeat());
        projectInfo.setHighestPrice(projectInfoFromHttp.getHighPrice());
        if (StringUtils.isNotBlank(projectInfoFromHttp.getProjectStartDate())) {
            projectInfo.setProjectStartDate(DateUtils.getDateFromStr(projectInfoFromHttp.getProjectStartDate(), "yyyy/MM/dd"));
        }
        if (StringUtils.isNotBlank(projectInfoFromHttp.getProjectEndDate())) {
            projectInfo.setProjectEndDate(DateUtils.getDateFromStr(projectInfoFromHttp.getProjectEndDate(), "yyyy/MM/dd"));
        }
        projectInfo.setSubClassifyName(projectInfoFromHttp.getSubClassifyName());
        projectInfo.setProjectName(projectList.getName());
        projectInfo.setBizId(projectList.getBizId());
        projectInfo.setTagName(projectList.getTagName());
        projectInfo.setTagRemark(projectList.getTagRemark());
        projectInfo.setProjectCity(projectList.getCity());
        projectInfo.setShortCity(projectList.getShortCity());
        projectInfo.setVenueName(projectList.getVenueName());
        projectInfo.setLowestPrice(projectList.getLowestPrice());
        if (StringUtils.isNotBlank(projectInfoFromHttp.getPreSaleTime())) {
            projectInfo.setPreSaleTime(DateUtils.getDateTimeFromStr(projectInfoFromHttp.getPreSaleTime(), "yyyy/MM/dd HH:mm:ss"));
        }
    }
}
