package com.openhis.web.document.appservice.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.core.common.core.domain.R;
import com.core.common.utils.AssignSeqUtil;
import com.core.common.utils.SecurityUtils;
import com.core.common.utils.bean.BeanUtils;
import com.openhis.common.enums.AssignSeqEnum;
import com.openhis.common.enums.DocUseRangeEnum;
import com.openhis.document.domain.DocDefinition;
import com.openhis.document.domain.DocDefinitionOrganization;
import com.openhis.document.service.IDocDefinitionOrganizationService;
import com.openhis.document.service.IDocDefinitionService;
import com.openhis.web.document.appservice.IDocDefinitionAppService;
import com.openhis.web.document.appservice.IDocDefinitionOrganizationAppService;
import com.openhis.web.document.dto.DirectoryNode;
import com.openhis.web.document.dto.DocDefinitionOrganizationDto;
import com.openhis.web.document.dto.DocDefinitionDto;
import com.openhis.web.document.dto.DocDefinitonParam;
import com.openhis.web.document.mapper.DocDefinitionAppMapper;
import com.openhis.web.document.util.DocumentDirectoryProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class DocDefinitionAppServiceImpl implements IDocDefinitionAppService {
    @Resource
    private IDocDefinitionService docDefinitionService;
    @Resource
    private IDocDefinitionOrganizationAppService docDefinitionOrganizationAppService;
    @Resource
    private IDocDefinitionOrganizationService docDefinitionOrganizationService;
    @Resource
    private DocDefinitionAppMapper docDefinitionAppMapper;


    @Autowired(required = false)
    private AssignSeqUtil assignSeqUtil;

    /**
     * 新增文书定义（含科室分配逻辑）
     */
    @Override
    public R<?> addDefinition(DocDefinitionDto definitionDto) {
        // 1. 基础参数校验（按必填优先级排序）
        if (definitionDto.getName() == null || definitionDto.getName().trim().isEmpty()) {
            return R.fail("新增文书定义失败：文书名称不能为空（或不能为空白字符）");
        }
        if (definitionDto.getVersion() == null || definitionDto.getVersion().trim().isEmpty()) {
            return R.fail("新增文书定义失败：文书版本号不能为空（或不能为空白字符）");
        }
        if (definitionDto.getVueRouter() == null || definitionDto.getVueRouter().trim().isEmpty()) {
            return R.fail("新增文书定义失败：文书路由不能为空（或不能为空白字符）");
        }
        if (definitionDto.getUseRangeEnum() != null && DocUseRangeEnum.DEPT_USE.getValue().equals(definitionDto.getUseRangeEnum()) && definitionDto.getOrganizationIds() == null) {
            return R.fail("新增文书定义失败：科室分配时，科室不能为空");
        }

        // 2. 校验"名称+版本号"唯一性（避免重复创建）
        long duplicateCount = docDefinitionService.lambdaQuery()
                .eq(DocDefinition::getName, definitionDto.getName().trim())
                .eq(DocDefinition::getVersion, definitionDto.getVersion().trim())
                .count();
        if (duplicateCount > 0) {
            log.warn("新增文书定义失败：名称={}、版本号={}的文书已存在",
                    definitionDto.getName(), definitionDto.getVersion());
            return R.fail("新增文书定义失败：相同名称和版本号的文书已存在，请修改后重试");
        }

        // 3. 补充默认值（避免null字段插入数据库）
        if (definitionDto.getDisplayOrder() == null) {
            definitionDto.setDisplayOrder(0);
        }
        if (definitionDto.getIsValid() == null) {
            definitionDto.setIsValid(0); // 0-默认无效，需根据业务确认是否改为1
        }

        // 4. 封装文书定义实体（生成业务编号）
        DocDefinition docDefinition = new DocDefinition();
        // 校验AssignSeqUtil是否注入（避免空指针）
        if (assignSeqUtil == null) {
            log.error("新增文书定义失败：AssignSeqUtil工具类未注入，无法生成业务编号");
            return R.fail("新增文书定义失败：系统工具类异常，无法生成业务编号");
        }
        String busNo = assignSeqUtil.getSeq(AssignSeqEnum.PURCHASE_DOCUMENT.getPrefix(), 10);
        docDefinition.setBusNo(busNo);
        docDefinition.setName(definitionDto.getName().trim());
        docDefinition.setVersion(definitionDto.getVersion().trim());
        docDefinition.setDisplayOrder(definitionDto.getDisplayOrder());
        docDefinition.setHospitalId(SecurityUtils.getLoginUser().getHospitalId());
        docDefinition.setIsValid(definitionDto.getIsValid());
        docDefinition.setVueRouter(definitionDto.getVueRouter().trim());
        docDefinition.setPrimaryMenuEnum(definitionDto.getPrimaryMenuEnum());
        docDefinition.setSubMenu(definitionDto.getSubMenu());
        docDefinition.setUseRangeEnum(definitionDto.getUseRangeEnum());
        docDefinition.setDoctorPermissionEnum(definitionDto.getDoctorPermissionEnum());
        docDefinition.setNursingPermissionEnum(definitionDto.getNursingPermissionEnum());
        docDefinition.setMedicalPermissionEnum(definitionDto.getMedicalPermissionEnum());
        docDefinition.setPharmacistPermissionEnum(definitionDto.getPharmacistPermissionEnum());

        // 5. 保存文书定义
        boolean saveSuccess = docDefinitionService.save(docDefinition);
        if (!saveSuccess) {
            log.error("新增文书定义失败：数据库保存异常（名称={}, 版本号={}, 业务编号={}",
                    definitionDto.getName(), definitionDto.getVersion(), busNo);
            return R.fail("新增文书定义失败：数据库保存操作异常");
        }

        // 6. 科室分配（仅当使用范围为"科室级"时执行）
        if (DocUseRangeEnum.DEPT_USE.getValue().equals(definitionDto.getUseRangeEnum())
                && definitionDto.getOrganizationIds() != null
                && !definitionDto.getOrganizationIds().isEmpty()) {
            DocDefinitionOrganizationDto orgDto = new DocDefinitionOrganizationDto();
            orgDto.setBusNo(busNo);
            orgDto.setDefinitionId(docDefinition.getId());
            orgDto.setOrganizationIds(definitionDto.getOrganizationIds());
            // 复用科室分配服务的新增逻辑，直接返回结果
            return docDefinitionOrganizationAppService.add(orgDto);
        }

        return R.ok("新增文书定义成功");
    }


    /**
     * 修改文书定义（版本号冲突时自动新增，含科室分配更新）
     */
    @Override
    public R<?> updateDefinition(DocDefinitionDto definitionDto) {
        // 1. 基础参数校验（修改必传字段）
        if (definitionDto.getId() == null) {
            return R.fail("修改文书定义失败：文书ID不能为空");
        }
        if (definitionDto.getName() == null || definitionDto.getName().trim().isEmpty()) {
            return R.fail("修改文书定义失败：文书名称不能为空（或不能为空白字符）");
        }
        if (definitionDto.getVersion() == null || definitionDto.getVersion().trim().isEmpty()) {
            return R.fail("修改文书定义失败：文书版本号不能为空（或不能为空白字符）");
        }
        if (definitionDto.getVueRouter() == null || definitionDto.getVueRouter().trim().isEmpty()) {
            return R.fail("修改文书定义失败：文书路由不能为空（或不能为空白字符）");
        }
        if (definitionDto.getBusNo() == null || definitionDto.getBusNo().trim().isEmpty()) {
            return R.fail("修改文书定义失败：文书业务编号不能为空（或不能为空白字符）");
        }
        if (definitionDto.getUseRangeEnum() != null && DocUseRangeEnum.DEPT_USE.getValue().equals(definitionDto.getUseRangeEnum()) && definitionDto.getOrganizationIds() == null) {
            return R.fail("修改文书定义失败：科室分配时，科室不能为空");
        }
        // 2. 校验文书是否存在
        DocDefinition existingDoc = docDefinitionService.getById(definitionDto.getId());
        if (existingDoc == null) {
            log.warn("修改文书定义失败：未找到ID={}的文书记录", definitionDto.getId());
            return R.fail("修改文书定义失败：待修改的文书记录不存在");
        }

        // 3. 版本号冲突处理（版本号不一致时，转为新增逻辑）
        if (!existingDoc.getVersion().trim().equals(definitionDto.getVersion().trim())) {
            log.info("修改文书定义：版本号冲突（原版本={}, 新版本={}），自动执行新增逻辑",
                    existingDoc.getVersion(), definitionDto.getVersion());
            // 新增前清空ID，避免覆盖原有记录
            definitionDto.setId(null);
            return addDefinition(definitionDto);
        }

        // 4. 补充默认值
        if (definitionDto.getDisplayOrder() == null) {
            definitionDto.setDisplayOrder(0);
        }
        if (definitionDto.getIsValid() == null) {
            definitionDto.setIsValid(0);
        }

        // 5. 封装修改后的数据
        existingDoc.setBusNo(definitionDto.getBusNo().trim());
        existingDoc.setName(definitionDto.getName().trim());
        existingDoc.setVersion(definitionDto.getVersion().trim());
        existingDoc.setDisplayOrder(definitionDto.getDisplayOrder());
        existingDoc.setHospitalId(SecurityUtils.getLoginUser().getHospitalId());
        existingDoc.setIsValid(definitionDto.getIsValid());
        existingDoc.setVueRouter(definitionDto.getVueRouter().trim());
        existingDoc.setPrimaryMenuEnum(definitionDto.getPrimaryMenuEnum());
        existingDoc.setSubMenu(definitionDto.getSubMenu());
        existingDoc.setUseRangeEnum(definitionDto.getUseRangeEnum());
        existingDoc.setDoctorPermissionEnum(definitionDto.getDoctorPermissionEnum());
        existingDoc.setNursingPermissionEnum(definitionDto.getNursingPermissionEnum());
        existingDoc.setMedicalPermissionEnum(definitionDto.getMedicalPermissionEnum());
        existingDoc.setPharmacistPermissionEnum(definitionDto.getPharmacistPermissionEnum());

        // 6. 执行修改
        boolean updateSuccess = docDefinitionService.updateById(existingDoc);
        if (!updateSuccess) {
            log.error("修改文书定义失败：数据库更新异常（ID={}, 业务编号={}",
                    definitionDto.getId(), definitionDto.getBusNo());
            return R.fail("修改文书定义失败：数据库更新操作异常");
        } else {
            // 7. 更新科室分配（仅当使用范围为"科室级"时执行）
            DocDefinitionOrganizationDto orgDto = new DocDefinitionOrganizationDto();
            orgDto.setBusNo(existingDoc.getBusNo());
            orgDto.setDefinitionId(existingDoc.getId());
            orgDto.setOrganizationIds(definitionDto.getOrganizationIds());
            // 复用科室分配服务的更新逻辑（先删后加，全量覆盖）
            return docDefinitionOrganizationAppService.updateOrganization(orgDto);
        }
    }

    @Override
    public R<?> deleteDefinition(Long id) {
        // 1. 参数校验
        if (id == null) {
            return R.fail("删除文书定义失败：文书ID不能为空");
        }
        boolean result = docDefinitionService.removeById(id);
        if (result) {
            log.info("删除文书定义成功：ID={}", id);
            return R.ok("删除文书定义成功");
        } else {
            log.error("删除文书定义失败：数据库删除异常（ID={})", id);
            return R.fail("删除文书定义失败：数据库删除操作异常");
        }
    }

    /**
     * 获取文书定义树形列表（按目录结构组织）
     */
    @Override
    public R<?> getTreeList(DocDefinitonParam param) {
        // 1. 获取当前登录用户的医院ID（避免跨医院查询）
        Long hospitalId = SecurityUtils.getLoginUser().getHospitalId();
        if (hospitalId == null) {
            log.warn("获取文书定义树形列表失败：当前登录用户未关联医院ID");
            return R.fail("获取文书定义树形列表失败：当前用户未关联医院，请重新登录");
        }

        // 2. 数据库查询文书定义列表
        List<DocDefinitionDto> docList = docDefinitionAppMapper.getDefinationList(
                param.getUseRanges(),
                param.getOrganizationId(),
                hospitalId,
                param.getName(),
                param.getPrimaryMenuEnum()
        );

        // 3. 构建树形结构（空列表时返回空树，避免空指针）
        List<DirectoryNode> treeNodes = new ArrayList<>();
        if (docList != null && !docList.isEmpty()) {
            treeNodes = DocumentDirectoryProcessor.buildDocumentDirectory(docList);
            log.info("获取文书定义树形列表成功：医院ID={}, 文书数量={}, 树形节点数量={}",
                    hospitalId, docList.size(), treeNodes.size());
        } else {
            log.info("获取文书定义树形列表成功：医院ID={}, 暂无匹配的文书定义", hospitalId);
        }

        return R.ok(treeNodes, "获取文书定义树形列表成功");
    }

    /**
     * 根据ID获取文书定义详情（含已分配科室ID列表）
     */
    @Override
    public R<?> getDefinitionDetailById(Long id) {
        // 1. 参数校验
        if (id == null) {
            return R.fail("获取文书定义详情失败：文书ID不能为空");
        }

        // 2. 调用私有方法获取详情（含科室ID）
        DocDefinitionDto docDto = getDefinitionById(id);
        if (docDto == null) {
            log.warn("获取文书定义详情失败：未找到ID={}的文书记录", id);
            return R.fail("获取文书定义详情失败：未查询到对应的文书定义信息");
        }

        log.info("获取文书定义详情成功：ID={}, 名称={}, 业务编号={}",
                id, docDto.getName(), docDto.getBusNo());
        return R.ok(docDto, "获取文书定义详情成功");
    }

    /**
     * 私有方法：根据ID查询文书定义（含已分配科室ID列表）
     */
    public DocDefinitionDto getDefinitionById(Long id) {
        // 1. 查询文书定义主信息
        DocDefinition doc = docDefinitionService.getById(id);
        if (doc == null) {
            log.debug("根据ID查询文书定义失败：ID={}的文书不存在", id);
            return null;
        }

        // 2. 查询该文书已分配的科室ID列表
        LambdaQueryWrapper<DocDefinitionOrganization> orgWrapper = new LambdaQueryWrapper<>();
        orgWrapper.eq(DocDefinitionOrganization::getDefinitionId, id)
                .eq(DocDefinitionOrganization::getBusNo, doc.getBusNo());
        List<DocDefinitionOrganization> orgList = docDefinitionOrganizationService.list(orgWrapper);

        // 3. 提取科室ID并封装DTO
        List<Long> orgIdList = new ArrayList<>();
        for (DocDefinitionOrganization org : orgList) {
            orgIdList.add(org.getOrganizationId());
        }

        DocDefinitionDto docDto = new DocDefinitionDto();
        BeanUtils.copyProperties(doc, docDto);
        docDto.setOrganizationIds(orgIdList);

        return docDto;
    }
}