package com.nbport.zgwl.manifest.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nbport.zgwl.common.PageResult;
import com.nbport.zgwl.exception.ServiceException;
import com.nbport.zgwl.manifest.dto.ContractTemplateDto;
import com.nbport.zgwl.manifest.dto.ContractTemplateQueryDto;
import com.nbport.zgwl.manifest.dto.TemplateOrgOptionDto;
import com.nbport.zgwl.manifest.handler.ContractTemplateDataHandler;
import com.nbport.zgwl.manifest.mapper.ContractTemplateMapper;
import com.nbport.zgwl.manifest.utils.ManifestCodeUtils;
import com.nbport.zgwl.manifest.utils.ManifestJsonUtils;
import com.nbport.zgwl.manifest.utils.ManifestManageConstants;
import com.nbport.zgwl.utils.AdminSecurityManage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 模板管理 Service 实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ContractTemplateServiceImpl implements ContractTemplateService {

    private final ContractTemplateMapper contractTemplateMapper;

    private final ContractTemplateDataHandler contractTemplateDataHandler;

    private final AdminSecurityManage adminSecurityManage;

    /**
     * 内存中的组织树（扁平化节点列表），懒加载
     */
    private List<OrgNode> orgTreeCache;

    /**
     * 分页查询模板列表
     * 自动根据当前用户所属组织过滤发布范围
     */
    @Override
    public PageResult<ContractTemplateDto> queryTemplateList(ContractTemplateQueryDto queryDto) {
        // 自动注入当前用户可见的组织 ID（含子级）
        if (queryDto.getVisibleOrgIds() == null || queryDto.getVisibleOrgIds().isEmpty()) {
            queryDto.setVisibleOrgIds(computeVisibleOrgIds());
        }

        Page<ContractTemplateDto> page = new Page<>(queryDto.getPageNo(), queryDto.getPageSize());
        Page<ContractTemplateDto> resultPage = (Page<ContractTemplateDto>) contractTemplateMapper.selectTemplatePage(page, queryDto);
        PageResult<ContractTemplateDto> pageResult = new PageResult<>(resultPage);
        contractTemplateDataHandler.fillUiFields(pageResult.getData());
        return pageResult;
    }

    /** 已发布的模板列表 */
    @Override
    public List<ContractTemplateDto> queryPublishedTemplates() {
        List<ContractTemplateDto> templates = contractTemplateMapper.selectPublishedTemplates(computeVisibleOrgIds());
        contractTemplateDataHandler.fillUiFields(templates);
        return templates;
    }

    /** 获取模板详情（含发布范围、变量映射的解析结果） */
    @Override
    public ContractTemplateDto getTemplateDetail(Long id) {
        ContractTemplateDto template = contractTemplateMapper.selectTemplateById(id);
        if (template == null) {
            throw new ServiceException("模板不存在");
        }
        contractTemplateDataHandler.fillUiFields(template);
        return template;
    }

    /** 新增模板（自动生成模板编号、保存 JSON 字段） */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContractTemplateDto createTemplate(ContractTemplateDto template) {
        contractTemplateDataHandler.normalizeBeforeSave(template);
        contractTemplateDataHandler.fillOrgNamesByIds(template, queryOrgOptions());
        contractTemplateDataHandler.validateForSave(template);

        LocalDateTime now = LocalDateTime.now();
        template.setId(contractTemplateMapper.selectTemplateSeqNextVal());
        template.setTemplateCode(ManifestCodeUtils.buildTemplateCode(template.getContractType()));
        template.setCreateBy(ManifestManageConstants.DEFAULT_OPERATOR);
        template.setCreatedTime(now);
        template.setUpdatedBy(ManifestManageConstants.DEFAULT_OPERATOR);
        template.setUpdatedTime(now);
        template.setDelFlag(ManifestManageConstants.DEL_FLAG_NORMAL);
        saveJsonFields(template);

        contractTemplateMapper.insertTemplate(template);
        return getTemplateDetail(template.getId());
    }

    /** 修改模板（保留原有的 templateCode、创建人、创建时间不变） */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContractTemplateDto updateTemplate(ContractTemplateDto template) {
        if (template.getId() == null) {
            throw new ServiceException("修改模板时 id 不能为空");
        }

        ContractTemplateDto dbTemplate = contractTemplateMapper.selectTemplateById(template.getId());
        if (dbTemplate == null) {
            throw new ServiceException("模板不存在");
        }

        contractTemplateDataHandler.normalizeBeforeSave(template);
        contractTemplateDataHandler.fillOrgNamesByIds(template, queryOrgOptions());
        contractTemplateDataHandler.validateForSave(template);

        template.setTemplateCode(dbTemplate.getTemplateCode());
        template.setCreateBy(dbTemplate.getCreateBy());
        template.setCreatedTime(dbTemplate.getCreatedTime());
        template.setUpdatedBy(ManifestManageConstants.DEFAULT_OPERATOR);
        template.setUpdatedTime(LocalDateTime.now());
        template.setDelFlag(dbTemplate.getDelFlag());
        saveJsonFields(template);

        contractTemplateMapper.updateTemplate(template);
        return getTemplateDetail(template.getId());
    }

    /** 切换模板状态（draft / published / disabled） */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContractTemplateDto changeTemplateStatus(Long id, String status) {
        if (!ManifestManageConstants.STATUS_DRAFT.equals(status)
                && !ManifestManageConstants.STATUS_PUBLISHED.equals(status)
                && !ManifestManageConstants.STATUS_DISABLED.equals(status)) {
            throw new ServiceException("模板状态不合法");
        }

        ContractTemplateDto dbTemplate = contractTemplateMapper.selectTemplateById(id);
        if (dbTemplate == null) {
            throw new ServiceException("模板不存在");
        }

        contractTemplateMapper.updateTemplateStatus(
                id,
                status,
                ManifestManageConstants.DEFAULT_OPERATOR,
                LocalDateTime.now()
        );
        return getTemplateDetail(id);
    }

    /** 删除模板（逻辑删除） */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTemplate(Long id) {
        ContractTemplateDto dbTemplate = contractTemplateMapper.selectTemplateById(id);
        if (dbTemplate == null) {
            throw new ServiceException("模板不存在");
        }
        contractTemplateMapper.deleteTemplateById(
                id,
                ManifestManageConstants.DEFAULT_OPERATOR,
                LocalDateTime.now(),
                ManifestManageConstants.DEL_FLAG_DELETED
        );
    }

    /**
     * 获取发布范围组织选项（扁平列表，供发布范围下拉使用）
     * 数据来源于组织树，平铺所有节点
     */
    @Override
    public List<TemplateOrgOptionDto> queryOrgOptions() {
        List<OrgNode> flatNodes = getFlatOrgTree();
        return flatNodes.stream()
                .map(node -> new TemplateOrgOptionDto(String.valueOf(node.id), node.orgName))
                .collect(Collectors.toList());
    }

    // ========== 组织树与权限计算 ==========

    /**
     * 计算当前用户可见的组织 ID 列表。
     * 规则：用户所属组织 + 所有祖先组织。
     * 因为发布范围选择上级时，其所有子部门都可见，
     * 所以对于用户来说，能看到的模板是「发布范围包含用户所属组织或其任一祖先」的模板。
     */
    private List<String> computeVisibleOrgIds() {
        String userOrgId = adminSecurityManage.getUser().getSysOrgEntity().getId();
        if (userOrgId == null) {
            return Collections.emptyList();
        }

        List<OrgNode> flatNodes = getFlatOrgTree();
        Map<String, OrgNode> nodeMap = new HashMap<>();
        for (OrgNode node : flatNodes) {
            nodeMap.put(String.valueOf(node.id), node);
        }

        // 收集当前用户所属组织及其所有祖先
        Set<String> visible = new HashSet<>();
        String currentId = userOrgId;
        while (currentId != null && nodeMap.containsKey(currentId)) {
            visible.add(currentId);
            OrgNode node = nodeMap.get(currentId);
            currentId = node.parentId != null ? String.valueOf(node.parentId) : null;
        }

        List<String> result = new ArrayList<>(visible);
        log.debug("当前用户 orgId={}, 可见组织列表={}", userOrgId, result);
        return result;
    }

    /**
     * 获取扁平化的组织树节点列表（线程安全懒加载）
     * 注意：必须与 AdminOrgController 中的组织树数据保持一致
     */
    private synchronized List<OrgNode> getFlatOrgTree() {
        if (orgTreeCache != null) {
            return orgTreeCache;
        }
        // 从 AdminOrgController 的 mock 数据构建（后续可替换为数据库或接口调用）
        orgTreeCache = buildFlatOrgTree();
        return orgTreeCache;
    }

    /**
     * 构建扁平组织树（与 AdminOrgController 的 mock 数据保持一致）
     */
    private List<OrgNode> buildFlatOrgTree() {
        List<OrgNode> nodes = new ArrayList<>();

        // 根节点
        nodes.add(new OrgNode(1L, "浙江海港物流集团有限公司X", 0L));

        // 二级节点
        nodes.add(new OrgNode(47L, "永康陆港国际物流有限公司", 1L));
        nodes.add(new OrgNode(138L, "永康物流分公司", 47L));

        nodes.add(new OrgNode(48L, "宁波港国际物流有限公司诸暨业务点", 1L));
        nodes.add(new OrgNode(49L, "宁波港国际物流有限公司兰溪业务点", 48L));

        nodes.add(new OrgNode(51L, "丽水陆港国际物流有限责任公司", 1L));
        nodes.add(new OrgNode(52L, "衢州通港国际物流有限公司", 1L));

        nodes.add(new OrgNode(58L, "浙港物流浙中北大区", 1L));
        nodes.add(new OrgNode(59L, "浙江兴港国际货运代理有限公司嘉兴分公司", 58L));
        nodes.add(new OrgNode(60L, "宁波港铁路有限公司绍兴分公司", 58L));

        nodes.add(new OrgNode(68L, "浙港物流江苏大区", 1L));
        nodes.add(new OrgNode(69L, "浙港（江苏）国际供应链管理有限公司", 68L));
        nodes.add(new OrgNode(71L, "盐城海铁", 69L));
        nodes.add(new OrgNode(72L, "浙港物流江苏其他", 68L));

        nodes.add(new OrgNode(70L, "海安海铁", 1L));
        nodes.add(new OrgNode(75L, "宁波港国际物流有限公司徐州分公司", 1L));

        nodes.add(new OrgNode(76L, "浙港物流湘赣大区", 1L));
        nodes.add(new OrgNode(77L, "宁波港铁路有限公司--向塘/贵溪/赣州/宜春西/鹰潭南/萍乡/景德镇东/新余/樟树/湘潭/株洲北/长沙北/岳阳", 76L));
        nodes.add(new OrgNode(78L, "江西上饶海港物流有限公司", 76L));

        nodes.add(new OrgNode(23L, "浙港物流安徽大区2", 1L));
        nodes.add(new OrgNode(43L, "宁波港铁路有限公司---蚌埠/洛阳/青龙山/萧山", 23L));
        nodes.add(new OrgNode(44L, "宁波港铁路有限公司---芜湖西/铜城闸/马鞍山", 23L));
        nodes.add(new OrgNode(45L, "宣城市浙皖国际陆港供应链管理有限公司", 23L));

        nodes.add(new OrgNode(321L, "汇海通-华峙", 1L));
        nodes.add(new OrgNode(382L, "11", 1L));
        nodes.add(new OrgNode(383L, "测试2", 1L));
        nodes.add(new OrgNode(181L, "东华", 1L));
        nodes.add(new OrgNode(182L, "港联捷", 1L));
        nodes.add(new OrgNode(46L, "浙江义乌国际公铁联运有限公司", 1L));
        nodes.add(new OrgNode(50L, "新安江业务点", 1L));

        nodes.add(new OrgNode(53L, "浙港物流华中大区", 1L));
        nodes.add(new OrgNode(56L, "宁波港国际物流有限公司襄阳分公司", 53L));
        nodes.add(new OrgNode(57L, "襄阳业务点", 56L));
        nodes.add(new OrgNode(54L, "湖北浙港供应链管理有限公司", 53L));
        nodes.add(new OrgNode(55L, "武铁浙港多式联运（河南）有限公司", 53L));

        nodes.add(new OrgNode(61L, "浙港物流浙西南大区", 1L));
        nodes.add(new OrgNode(62L, "浙港物流金华南", 61L));
        nodes.add(new OrgNode(63L, "浙港物流台州南", 61L));
        nodes.add(new OrgNode(64L, "宁波佰菲特国际货运代理有限公司", 63L));

        nodes.add(new OrgNode(65L, "宁波港国际物流有限公司合肥分公司", 1L));
        nodes.add(new OrgNode(66L, "六安安庆北业务点", 65L));

        nodes.add(new OrgNode(67L, "江山无水港国际物流有限公司", 1L));

        nodes.add(new OrgNode(73L, "浙港物流西部大区", 1L));
        nodes.add(new OrgNode(74L, "宁波港铁路有限公司---重庆/城厢/白银市/西安/宜兴", 73L));

        return nodes;
    }

    /** 将 JSON 字段转为文本存入数据库 */
    private void saveJsonFields(ContractTemplateDto template) {
        template.setPublishOrgIdsJson(ManifestJsonUtils.toJson(template.getPublishOrgIds()));
        template.setPublishOrgNamesJson(ManifestJsonUtils.toJson(template.getPublishOrgNames()));
        template.setVariableMappingsJson(ManifestJsonUtils.toJson(template.getVariableMappings()));
    }

    /**
     * 内部组织节点
     */
    private static class OrgNode {
        private final Long id;
        private final String orgName;
        private final Long parentId;

        OrgNode(Long id, String orgName, Long parentId) {
            this.id = id;
            this.orgName = orgName;
            this.parentId = parentId;
        }
    }
}
