package com.yeejoin.amos.boot.module.jyjc.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.biz.common.bo.CompanyBo;
import com.yeejoin.amos.boot.module.common.api.constant.TZSCommonConstant;
import com.yeejoin.amos.boot.module.common.api.dto.BaseEnterpriseCertDto;
import com.yeejoin.amos.boot.module.jyjc.api.common.BizCommonConstant;
import com.yeejoin.amos.boot.module.jyjc.api.entity.JyjcInspectionHistory;
import com.yeejoin.amos.boot.module.jyjc.api.entity.JyjcOpeningApplication;
import com.yeejoin.amos.boot.module.jyjc.api.enums.OpenBizTypeEnumV2;
import com.yeejoin.amos.boot.module.jyjc.api.model.JyjcBizManageModel;
import com.yeejoin.amos.boot.module.jyjc.api.model.JyjcOpeningApplicationModel;
import com.yeejoin.amos.boot.module.ymt.api.entity.BaseUnitLicence;
import com.yeejoin.amos.boot.module.ymt.api.enums.FlowStatusEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.BaseUnitLicenceMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.typroject.tyboot.core.rdbms.orm.entity.BaseEntity;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class JyjcBizManageServiceImpl {

    private static final String TY = "停用";

    private static final String QY = "启用";

    private final JyjcOpeningApplicationServiceImpl openingApplicationService;

    private final JyjcInspectionHistoryServiceImpl inspectionHistoryService;

    private final RedissonClient redissonClient;

    private final BaseUnitLicenceMapper baseUnitLicenceMapper;

    public IPage<?> pageList(Page<JyjcBizManageModel> page, CompanyBo company, JyjcOpeningApplicationModel model) {
        Page<JyjcOpeningApplication> pageApp = new Page<>(page.getCurrent(), page.getSize());
        LambdaQueryWrapper<JyjcOpeningApplication> queryWrapper = new LambdaQueryWrapper<>();
        this.setIdentify(company, queryWrapper);
        queryWrapper.eq(JyjcOpeningApplication::getStatus, FlowStatusEnum.TO_BE_FINISHED.getName());
        queryWrapper.like(StringUtils.isNotEmpty(model.getUnitCodeName()), JyjcOpeningApplication::getUnitCodeName, model.getUnitCodeName());
        queryWrapper.eq(StringUtils.isNotEmpty(model.getOpenBizType()), JyjcOpeningApplication::getOpenBizType, model.getOpenBizType());
        IPage<JyjcOpeningApplication> res = openingApplicationService.page(pageApp, queryWrapper);
        List<JyjcBizManageModel> manageModels = res.getRecords().stream().map(r -> {
            JyjcBizManageModel bizManageModel = BeanUtil.copyProperties(r, JyjcBizManageModel.class);
            setAreaStatusByIdentify(company, r, bizManageModel);
            bizManageModel.setCompanyCode(company.getCompanyCode());
            bizManageModel.setOpenBizTypeName(Optional.of(OpenBizTypeEnumV2.getOneByCode(bizManageModel.getOpenBizType())).map(OpenBizTypeEnumV2::getDescription).orElse(""));
            return bizManageModel;
        }).collect(Collectors.toList());
        page.setRecords(manageModels);
        page.setTotal(res.getTotal());
        return page;
    }

    private static void setAreaStatusByIdentify(CompanyBo company, JyjcOpeningApplication r, JyjcBizManageModel bizManageModel) {
        if (TZSCommonConstant.SHAN_XI_REGION_CODE.equals(company.getCompanyCode())) {
            bizManageModel.setAreaStatus(QY);
        } else {
            if (r.getExclusionRegion() != null && r.getExclusionRegion().contains(company.getCompanyCode())) {
                bizManageModel.setAreaStatus(TY);
            } else {
                bizManageModel.setAreaStatus(QY);
            }
        }
    }

    private void setIdentify(CompanyBo company, LambdaQueryWrapper<JyjcOpeningApplication> queryWrapper) {
        if (!TZSCommonConstant.SHAN_XI_REGION_CODE.equals(company.getCompanyCode())) {
            queryWrapper.and(w ->
                    w.like(JyjcOpeningApplication::getDetectionRegion, company.getCompanyCode())
                            .or()
                            .like(JyjcOpeningApplication::getExclusionRegion, company.getCompanyCode()));
        }
    }

    public Boolean enable(String appSeq, CompanyBo company) {
        log.info("启用企业区域权限, appSeq: {}, company: {}", appSeq, company.getCompanyCode());
        String lockKey = "app:region:lock:" + appSeq;
        RLock lock = redissonClient.getLock(lockKey);
        try {
            boolean isLocked = lock.tryLock(0, 180, TimeUnit.SECONDS);
            // 解决并发问题：多个人同时操作一个单据
            if (!isLocked) {
                throw new BadRequest("其他机构同时在操作该业务，请稍后重试！");
            }
            JyjcOpeningApplication openingApplication = openingApplicationService.getById(appSeq);
            List<String> detectionRegion = openingApplication.getDetectionRegion();
            Set<String> detectionRegionSet = new HashSet<>(detectionRegion);
            detectionRegionSet.add(company.getCompanyCode());
            List<String> exclusionRegion = openingApplication.getExclusionRegion();
            if (exclusionRegion != null) {
                exclusionRegion.remove(company.getCompanyCode());
            }
            openingApplicationService.update(new LambdaUpdateWrapper<JyjcOpeningApplication>()
                    .eq(BaseEntity::getSequenceNbr, appSeq)
                    .set(JyjcOpeningApplication::getDetectionRegion, detectionRegionSet)
                    .set(JyjcOpeningApplication::getExclusionRegion, exclusionRegion));

        } catch (InterruptedException e) {
            log.error("启用企业区域失败：{}", e.getMessage(), e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return Boolean.TRUE;
    }

    public Boolean disable(String appSeq, CompanyBo company) {
        log.info("禁用企业区域权限, appSeq: {}, company: {}", appSeq, company.getCompanyCode());
        String lockKey = "app:region:lock:" + appSeq;
        RLock lock = redissonClient.getLock(lockKey);
        try {
            boolean isLocked = lock.tryLock(0, 180, TimeUnit.SECONDS);
            // 解决并发问题：解决并发问题：多个人同时操作一个单据
            if (!isLocked) {
                throw new BadRequest("其他机构同时在操作该业务，请稍后重试！");
            }
            JyjcOpeningApplication openingApplication = openingApplicationService.getById(appSeq);
            List<String> detectionRegion = openingApplication.getDetectionRegion();
            if (detectionRegion != null) {
                detectionRegion.remove(company.getCompanyCode());
            }
            List<String> exclusionRegion = openingApplication.getExclusionRegion();
            Set<String> exclusionRegionSet = new HashSet<>(exclusionRegion);
            exclusionRegion.add(company.getCompanyCode());
            openingApplicationService.update(new LambdaUpdateWrapper<JyjcOpeningApplication>()
                    .eq(BaseEntity::getSequenceNbr, appSeq)
                    .set(JyjcOpeningApplication::getDetectionRegion, detectionRegion)
                    .set(JyjcOpeningApplication::getExclusionRegion, exclusionRegionSet));
        } catch (InterruptedException e) {
            log.error("禁用企业区域失败：{}", e.getMessage(), e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return Boolean.TRUE;
    }

    public Boolean licenceEdit(String appSeq, List<BaseUnitLicence> licences) {
        JyjcOpeningApplication openingApplication = openingApplicationService.getById(appSeq);
        if (!openingApplication.getStatus().equals(FlowStatusEnum.TO_BE_FINISHED.getName())) {
            throw new BadRequest("开通状态已经变化，请刷新后重试！");
        }
        licences.forEach(licence -> {
            LambdaUpdateWrapper<BaseUnitLicence> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(com.yeejoin.amos.boot.biz.common.entity.BaseEntity::getSequenceNbr, licence.getSequenceNbr());
            updateWrapper.set(BaseUnitLicence::getLicenceState, licence.getLicenceState());
            baseUnitLicenceMapper.update(null, updateWrapper);
        });
        return Boolean.TRUE;
    }

    public Map<String, Object> licenceDetail(String appSeq) {
        Map<String, Object> res = new HashMap<>();
        List<BaseUnitLicence> baseUnitLicences = new ArrayList<>();
        JyjcOpeningApplication openingApplication = openingApplicationService.getById(appSeq);
        JyjcInspectionHistory history = inspectionHistoryService.getBySSeq(appSeq);
        if (history != null) {
            JSONObject hisData = history.getHistoryData();
            List<BaseEnterpriseCertDto> certDtos = hisData.getJSONArray(BizCommonConstant.UNIT_LICENCE_KEY).toJavaList(BaseEnterpriseCertDto.class);
            certDtos.forEach(certDto -> {
                List<Long> certSeqList = openingApplicationService.getCertFromHisData(openingApplication, certDto);
                if (!certSeqList.isEmpty()) {
                    List<BaseUnitLicence> baseUnitLicenceOne = baseUnitLicenceMapper.selectList(new LambdaQueryWrapper<BaseUnitLicence>().in(BaseUnitLicence::getEnterpriseCertSeq, certSeqList));
                    baseUnitLicences.addAll(baseUnitLicenceOne);
                }
            });
        }
        res.put("licences", baseUnitLicences);
        return res;
    }

    public Boolean expireDateEdit(String appSeq, String newExpiryDate) {
        LambdaUpdateWrapper<JyjcOpeningApplication> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(BaseEntity::getSequenceNbr, appSeq);
        updateWrapper.set(JyjcOpeningApplication::getExpiryDate, DateUtil.parseDate(newExpiryDate));
        openingApplicationService.update(updateWrapper);
        return Boolean.TRUE;
    }

    public Boolean detectionRegionEdit(String appSeq, String newDetectionRegion) {
        LambdaUpdateWrapper<JyjcOpeningApplication> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(BaseEntity::getSequenceNbr, appSeq);
        updateWrapper.set(JyjcOpeningApplication::getDetectionRegion, newDetectionRegion);
        openingApplicationService.update(updateWrapper);
        return Boolean.TRUE;
    }

    public JyjcBizManageModel getBasicInfo(String appSeq) {
        JyjcOpeningApplication openingApplication = openingApplicationService.getById(appSeq);
        return BeanUtil.copyProperties(openingApplication, JyjcBizManageModel.class);
    }
}
