package com.xly.erp.module.mod.service.impl;

import com.xly.erp.common.config.StubSecurityProperties;
import com.xly.erp.common.config.TenantProperties;
import com.xly.erp.common.exception.BizException;
import com.xly.erp.common.security.SecurityContextHelper;
import com.xly.erp.module.mod.dto.CreateModuleDTO;
import com.xly.erp.module.mod.dto.UpdateModuleDTO;
import com.xly.erp.module.mod.entity.Module;
import com.xly.erp.module.mod.vo.ModuleTreeVO;
import com.xly.erp.module.mod.mapper.ModuleMapper;
import com.xly.erp.module.mod.service.ModuleService;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
@Transactional(rollbackFor = Exception.class)
public class ModuleServiceImpl implements ModuleService {

    private static final Set<String> DISPLAY_TYPES = Set.of("手机端", "前端业务", "系统配置", "接口");
    private static final int MAX_PARENT_DEPTH = 50;

    private final ModuleMapper moduleMapper;
    private final TenantProperties tenant;
    private final StubSecurityProperties stub;

    public ModuleServiceImpl(ModuleMapper moduleMapper,
                             TenantProperties tenant,
                             StubSecurityProperties stub) {
        this.moduleMapper = moduleMapper;
        this.tenant = tenant;
        this.stub = stub;
    }

    @Override
    public Integer create(CreateModuleDTO dto) {
        if (!DISPLAY_TYPES.contains(dto.getSDisplayType())) {
            throw new BizException(40010, "显示类型枚举不合法");
        }
        if (dto.getIParentId() != null && !moduleMapper.existsActiveById(dto.getIParentId())) {
            throw new BizException(40021, "父模块不存在或已删除");
        }

        Module m = new Module();
        m.setSBrandsId(tenant.getBrandsId());
        m.setSSubsidiaryId(tenant.getSubsidiaryId());
        m.setTCreateDate(LocalDateTime.now());
        m.setSDisplayType(dto.getSDisplayType());
        m.setSProcedureName(dto.getSProcedureName());
        m.setSModuleType(dto.getSModuleType());
        m.setSManageDeptEn(dto.getSManageDeptEn());
        m.setBShowPermission(dto.getBShowPermission() != null ? dto.getBShowPermission() : false);
        m.setSModuleNameZh(dto.getSModuleNameZh());
        m.setIParentId(dto.getIParentId());
        m.setISortOrder(dto.getISortOrder() != null ? dto.getISortOrder() : 0);
        m.setSCreatedBy(SecurityContextHelper.currentUserNo());
        m.setBDeleted(false);

        try {
            moduleMapper.insert(m);
        } catch (DuplicateKeyException e) {
            throw new BizException(40020, "存储过程名称已存在");
        }
        return m.getIIncrement();
    }

    @Override
    public Integer update(Integer id, UpdateModuleDTO dto) {
        Module original = moduleMapper.selectById(id);
        if (original == null || Boolean.TRUE.equals(original.getBDeleted())) {
            throw new BizException(40400, "模块不存在或已删除");
        }
        if (!DISPLAY_TYPES.contains(dto.getSDisplayType())) {
            throw new BizException(40010, "显示类型枚举不合法");
        }
        validateParent(id, dto.getIParentId());

        Module entity = new Module();
        entity.setIIncrement(id);
        entity.setSDisplayType(dto.getSDisplayType());
        entity.setSModuleType(dto.getSModuleType());
        entity.setSManageDeptEn(dto.getSManageDeptEn());
        entity.setBShowPermission(dto.getBShowPermission() != null ? dto.getBShowPermission() : false);
        entity.setSModuleNameZh(dto.getSModuleNameZh());
        entity.setIParentId(dto.getIParentId());
        entity.setISortOrder(dto.getISortOrder() != null ? dto.getISortOrder() : 0);

        moduleMapper.updateById(entity);
        return id;
    }

    @Override
    public void delete(Integer id) {
        Module original = moduleMapper.selectById(id);
        if (original == null || Boolean.TRUE.equals(original.getBDeleted())) {
            throw new BizException(40400, "模块不存在或已删除");
        }
        if (moduleMapper.hasActiveChildren(id)) {
            throw new BizException(40901, "模块仍有未删除子节点");
        }

        Module entity = new Module();
        entity.setIIncrement(id);
        entity.setBDeleted(true);
        entity.setTDeletedDate(LocalDateTime.now());
        entity.setSDeletedBy(SecurityContextHelper.currentUserNo());
        moduleMapper.updateById(entity);
    }

    @Override
    @Transactional(readOnly = true)
    public List<ModuleTreeVO> listTree(String keyword) {
        String normalized = keyword == null ? "" : keyword.trim();
        if (normalized.length() > 100) {
            throw new BizException(40001, "keyword 长度超过 100 字符");
        }
        List<Module> rows = moduleMapper.selectActiveByKeyword(normalized);
        Map<Integer, ModuleTreeVO> idIndex = new HashMap<>();
        for (Module m : rows) {
            idIndex.put(m.getIIncrement(), toTreeVO(m));
        }
        List<ModuleTreeVO> roots = new ArrayList<>();
        for (Module m : rows) {
            ModuleTreeVO vo = idIndex.get(m.getIIncrement());
            Integer parentId = m.getIParentId();
            if (parentId != null && idIndex.containsKey(parentId)) {
                idIndex.get(parentId).getChildren().add(vo);
            } else {
                roots.add(vo);
            }
        }
        return roots;
    }

    private ModuleTreeVO toTreeVO(Module m) {
        ModuleTreeVO vo = new ModuleTreeVO();
        vo.setIIncrement(m.getIIncrement());
        vo.setSModuleNameZh(m.getSModuleNameZh());
        vo.setSDisplayType(m.getSDisplayType());
        vo.setSManageDeptEn(m.getSManageDeptEn());
        vo.setIParentId(m.getIParentId());
        vo.setISortOrder(m.getISortOrder());
        return vo;
    }

    private void validateParent(Integer id, Integer parentId) {
        if (parentId == null) {
            return;
        }
        if (parentId.equals(id)) {
            throw new BizException(40021, "父模块不能指向自身");
        }
        if (!moduleMapper.existsActiveById(parentId)) {
            throw new BizException(40021, "父模块不存在或已删除");
        }
        Integer cur = moduleMapper.selectParentIdById(parentId);
        for (int depth = 0; cur != null; depth++) {
            if (cur.equals(id)) {
                throw new BizException(40021, "父模块链构成环路");
            }
            if (depth >= MAX_PARENT_DEPTH) {
                throw new BizException(40021, "父模块链超过最大层级");
            }
            cur = moduleMapper.selectParentIdById(cur);
        }
    }
}
