package com.agent.management.service.impl;

import com.agent.management.common.exception.BusinessException;
import com.agent.management.model.dto.TagExportDTO;
import com.agent.management.model.dto.TagExportDTO.TagGroupExport;
import com.agent.management.model.dto.TagExportDTO.TagNodeExport;
import com.agent.management.model.dto.TagImportDTO;
import com.agent.management.model.dto.TagImportResultDTO;
import com.agent.management.model.entity.Tag;
import com.agent.management.model.entity.TagAssignment;
import com.agent.management.model.entity.TagGroup;
import com.agent.management.model.vo.TagBriefVO;
import com.agent.management.repository.TagAssignmentRepository;
import com.agent.management.repository.TagGroupRepository;
import com.agent.management.repository.TagRepository;
import com.agent.management.service.TagService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class TagServiceImpl implements TagService {

    private final TagGroupRepository groupRepo;
    private final TagRepository tagRepo;
    private final TagAssignmentRepository assignmentRepo;

    // ========== 标签组 ==========

    @Override
    public List<TagGroup> listGroups() {
        return groupRepo.findAllByOrderBySortOrderAsc();
    }

    @Override
    public TagGroup createGroup(String name, String description) {
        long count = groupRepo.count();
        TagGroup group = new TagGroup();
        group.setName(name);
        group.setDescription(description);
        group.setSortOrder((int) count);

        // 自动创建同名根节点
        Tag root = new Tag();
        root.setGroupId(group.getId());
        root.setParentId(null);
        root.setName(name);
        root.setSortOrder(0);

        // 先保存 group 以获取 ID
        group.onCreate();
        group = groupRepo.save(group);

        root.setGroupId(group.getId());
        root.onCreate();
        tagRepo.save(root);

        return group;
    }

    @Override
    public TagGroup updateGroup(Long id, String name, String description) {
        TagGroup group = groupRepo.findById(id)
                .orElseThrow(() -> new BusinessException("标签组不存在"));
        group.setName(name);
        group.setDescription(description);

        // 同步更新根节点名称
        List<Tag> rootTags = tagRepo.findByParentIdOrderBySortOrderAsc(null);
        rootTags.stream()
                .filter(t -> t.getGroupId().equals(id))
                .findFirst()
                .ifPresent(root -> {
                    root.setName(name);
                    root.onUpdate();
                    tagRepo.save(root);
                });

        group.onUpdate();
        return groupRepo.save(group);
    }

    @Override
    public void deleteGroup(Long id) {
        tagRepo.deleteAllByGroupId(id);
        groupRepo.deleteById(id);
    }

    // ========== 标签节点 ==========

    @Override
    public List<Tag> listTags(Long groupId) {
        return tagRepo.findByGroupIdOrderBySortOrderAsc(groupId);
    }

    @Override
    public Tag createTag(Long groupId, Long parentId, String name) {
        groupRepo.findById(groupId)
                .orElseThrow(() -> new BusinessException("标签组不存在"));

        // 如果未指定 parentId，自动挂到该组的根节点下
        if (parentId == null) {
            List<Tag> rootTags = tagRepo.findByParentIdOrderBySortOrderAsc(null);
            Tag root = rootTags.stream()
                    .filter(t -> t.getGroupId().equals(groupId))
                    .findFirst()
                    .orElse(null);
            if (root != null) {
                parentId = root.getId();
            }
        }

        // 校验父节点存在且同组
        if (parentId != null) {
            Tag parent = tagRepo.findById(parentId)
                    .orElseThrow(() -> new BusinessException("父标签不存在"));
            if (!parent.getGroupId().equals(groupId)) {
                throw new BusinessException("父标签不属于该标签组");
            }
        }

        List<Tag> siblings = tagRepo.findByParentIdOrderBySortOrderAsc(parentId);

        Tag tag = new Tag();
        tag.setGroupId(groupId);
        tag.setParentId(parentId);
        tag.setName(name);
        tag.setSortOrder(siblings.size());
        tag.onCreate();
        return tagRepo.save(tag);
    }

    @Override
    public Tag updateTag(Long id, String name) {
        Tag tag = tagRepo.findById(id)
                .orElseThrow(() -> new BusinessException("标签不存在"));

        // 虚拟根节点（parentId=null）不可改名
        if (tag.getParentId() == null) {
            throw new BusinessException("标签组根节点不可重命名");
        }

        tag.setName(name);
        tag.onUpdate();
        return tagRepo.save(tag);
    }

    @Override
    public void deleteTag(Long id) {
        Tag tag = tagRepo.findById(id)
                .orElseThrow(() -> new BusinessException("标签不存在"));

        // 虚拟根节点（parentId=null）不可直接删除，应删除标签组
        if (tag.getParentId() == null) {
            throw new BusinessException("标签组根节点不可删除，请删除整个标签组");
        }

        // 递归删除所有子孙节点
        deleteDescendants(id);
        tagRepo.deleteById(id);
    }

    private void deleteDescendants(Long parentId) {
        List<Tag> children = tagRepo.findByParentIdOrderBySortOrderAsc(parentId);
        for (Tag child : children) {
            deleteDescendants(child.getId());
            tagRepo.deleteById(child.getId());
        }
    }

    @Override
    public Tag moveTag(Long id, Long newParentId, Integer sortOrder) {
        Tag tag = tagRepo.findById(id)
                .orElseThrow(() -> new BusinessException("标签不存在"));

        // 防止将节点移动到自己的子孙下
        if (newParentId != null && isDescendant(newParentId, id)) {
            throw new BusinessException("不能将标签移动到自己的子标签下");
        }

        tag.setParentId(newParentId);
        tag.setSortOrder(sortOrder);
        tag.onUpdate();
        return tagRepo.save(tag);
    }

    /** 检查 targetId 是否是 ancestorId 的子孙 */
    private boolean isDescendant(Long targetId, Long ancestorId) {
        List<Long> visited = new ArrayList<>();
        Long current = targetId;
        while (current != null) {
            if (current.equals(ancestorId)) return true;
            if (visited.contains(current)) break; // 防环
            visited.add(current);
            Tag t = tagRepo.findById(current).orElse(null);
            current = t != null ? t.getParentId() : null;
        }
        return false;
    }

    // ========== 导入导出 ==========

    @Override
    public TagExportDTO exportAll() {
        List<TagGroup> groups = groupRepo.findAllByOrderBySortOrderAsc();

        TagExportDTO export = new TagExportDTO();
        export.setExportedAt(LocalDateTime.now().toString());

        List<TagGroupExport> groupExports = new ArrayList<>();
        for (TagGroup group : groups) {
            TagGroupExport ge = new TagGroupExport();
            ge.setName(group.getName());
            ge.setDescription(group.getDescription());
            ge.setSortOrder(group.getSortOrder());

            // 加载该组所有标签，构建树
            List<Tag> allTags = tagRepo.findByGroupIdOrderBySortOrderAsc(group.getId());
            ge.setTags(buildTagTree(allTags));

            groupExports.add(ge);
        }

        export.setGroups(groupExports);
        return export;
    }

    @Override
    public TagImportResultDTO importTags(TagImportDTO request) {
        if (request.getData() == null || request.getData().getGroups() == null) {
            throw new BusinessException("导入数据不能为空");
        }

        TagImportResultDTO result = new TagImportResultDTO();
        Map<String, String> strategies = request.getStrategies() != null
                ? request.getStrategies() : Collections.emptyMap();

        // 查询现有标签组，按名称索引
        Map<String, TagGroup> existingByName = groupRepo.findAllByOrderBySortOrderAsc()
                .stream().collect(Collectors.toMap(TagGroup::getName, g -> g, (a, b) -> a));

        for (TagGroupExport groupExport : request.getData().getGroups()) {
            String name = groupExport.getName();
            TagGroup existing = existingByName.get(name);
            String strategy = strategies.getOrDefault(name, "create");

            if (existing != null) {
                switch (strategy) {
                    case "overwrite" -> importOverwrite(existing, groupExport, result);
                    case "merge" -> importMerge(existing, groupExport, result);
                    case "skip" -> {
                        result.setSkipped(result.getSkipped() + 1);
                        result.getDetails().add("跳过: " + name);
                    }
                    default -> {
                        // 默认 skip 避免误操作
                        result.setSkipped(result.getSkipped() + 1);
                        result.getDetails().add("跳过(冲突): " + name);
                    }
                }
            } else {
                importCreate(groupExport, result);
            }
        }

        return result;
    }

    /** 新建标签组 */
    private void importCreate(TagGroupExport groupExport, TagImportResultDTO result) {
        TagGroup group = createGroup(groupExport.getName(), groupExport.getDescription());
        // 导入子标签（根节点由 createGroup 自动创建，导入 children 到根节点下）
        Long groupId = group.getId();
        List<Tag> rootTags = tagRepo.findByParentIdOrderBySortOrderAsc(null);
        Tag root = rootTags.stream()
                .filter(t -> t.getGroupId().equals(groupId))
                .findFirst().orElse(null);

        if (root != null && groupExport.getTags() != null) {
            for (TagNodeExport child : groupExport.getTags()) {
                importTagNode(groupId, root.getId(), child);
            }
        }

        result.setCreated(result.getCreated() + 1);
        result.getDetails().add("新建: " + groupExport.getName());
    }

    /** 覆盖：删除原有标签组和所有标签，重新创建 */
    private void importOverwrite(TagGroup existing, TagGroupExport groupExport, TagImportResultDTO result) {
        Long groupId = existing.getId();
        // 删除旧组所有标签
        tagRepo.deleteAllByGroupId(groupId);
        groupRepo.deleteById(groupId);

        // 重新创建
        importCreate(groupExport, result);

        result.setCreated(result.getCreated() - 1); // 修正：这是覆盖，不是新建
        result.setOverwritten(result.getOverwritten() + 1);
        result.getDetails().set(result.getDetails().size() - 1,
                "覆盖: " + groupExport.getName());
    }

    /** 合并：逐层按名称匹配，已存在的保留，新的追加 */
    private void importMerge(TagGroup existing, TagGroupExport groupExport, TagImportResultDTO result) {
        Long groupId = existing.getId();

        if (groupExport.getTags() == null) {
            result.setMerged(result.getMerged() + 1);
            result.getDetails().add("合并(无变更): " + groupExport.getName());
            return;
        }

        // 找到根节点
        List<Tag> rootTags = tagRepo.findByParentIdOrderBySortOrderAsc(null);
        Tag root = rootTags.stream()
                .filter(t -> t.getGroupId().equals(groupId))
                .findFirst().orElse(null);

        if (root != null) {
            for (TagNodeExport childExport : groupExport.getTags()) {
                mergeTagNode(groupId, root.getId(), childExport);
            }
        }

        result.setMerged(result.getMerged() + 1);
        result.getDetails().add("合并: " + groupExport.getName());
    }

    /** 递归导入标签节点 */
    private void importTagNode(Long groupId, Long parentId, TagNodeExport nodeExport) {
        Tag tag = new Tag();
        tag.setGroupId(groupId);
        tag.setParentId(parentId);
        tag.setName(nodeExport.getName());
        tag.setSortOrder(nodeExport.getSortOrder() != null ? nodeExport.getSortOrder() : 0);
        tag.onCreate();
        tag = tagRepo.save(tag);

        if (nodeExport.getChildren() != null) {
            for (TagNodeExport child : nodeExport.getChildren()) {
                importTagNode(groupId, tag.getId(), child);
            }
        }
    }

    /** 递归合并标签节点：按名称匹配，存在则递归合并子节点，不存在则创建 */
    private void mergeTagNode(Long groupId, Long parentId, TagNodeExport nodeExport) {
        // 查找同级是否有同名标签
        List<Tag> siblings = tagRepo.findByParentIdOrderBySortOrderAsc(parentId);
        Tag existing = siblings.stream()
                .filter(t -> t.getName().equals(nodeExport.getName()))
                .findFirst().orElse(null);

        if (existing != null) {
            // 同名已存在，递归合并子节点
            if (nodeExport.getChildren() != null) {
                for (TagNodeExport child : nodeExport.getChildren()) {
                    mergeTagNode(groupId, existing.getId(), child);
                }
            }
        } else {
            // 不存在，创建
            importTagNode(groupId, parentId, nodeExport);
        }
    }

    /** 将扁平标签列表构建为嵌套树结构 */
    private List<TagNodeExport> buildTagTree(List<Tag> allTags) {
        // 找出根节点（parentId 为 null 的）
        List<Tag> roots = allTags.stream()
                .filter(t -> t.getParentId() == null)
                .toList();

        List<TagNodeExport> result = new ArrayList<>();
        for (Tag root : roots) {
            // 根节点本身是标签组同名节点，导出其子节点作为顶层
            List<Tag> children = allTags.stream()
                    .filter(t -> root.getId().equals(t.getParentId()))
                    .sorted(Comparator.comparingInt(t -> t.getSortOrder() != null ? t.getSortOrder() : 0))
                    .toList();

            for (Tag child : children) {
                result.add(toTagNodeExport(child, allTags));
            }
        }
        return result;
    }

    /** 递归转换 Tag 实体为导出节点 */
    private TagNodeExport toTagNodeExport(Tag tag, List<Tag> allTags) {
        TagNodeExport node = new TagNodeExport();
        node.setName(tag.getName());
        node.setSortOrder(tag.getSortOrder());

        List<Tag> children = allTags.stream()
                .filter(t -> tag.getId().equals(t.getParentId()))
                .sorted(Comparator.comparingInt(t -> t.getSortOrder() != null ? t.getSortOrder() : 0))
                .toList();

        if (!children.isEmpty()) {
            node.setChildren(children.stream()
                    .map(c -> toTagNodeExport(c, allTags))
                    .toList());
        }
        return node;
    }

    // ========== 打标 ==========

    @Override
    public void setTags(String entityType, String entityId, List<Long> tagIds) {
        // 先删除旧的关联
        assignmentRepo.deleteAllByEntityTypeAndEntityId(entityType, entityId);

        // 创建新的关联
        if (tagIds != null) {
            for (Long tagId : tagIds) {
                TagAssignment assignment = new TagAssignment();
                assignment.setEntityType(entityType);
                assignment.setEntityId(entityId);
                assignment.setTagId(tagId);
                assignment.onCreate();
                assignmentRepo.save(assignment);
            }
        }
    }

    @Override
    public List<TagBriefVO> getEntityTags(String entityType, String entityId) {
        List<TagAssignment> assignments = assignmentRepo.findByEntityTypeAndEntityId(entityType, entityId);
        if (assignments.isEmpty()) {
            return List.of();
        }

        // 批量查询标签和标签组
        List<TagBriefVO> result = new ArrayList<>();
        for (TagAssignment a : assignments) {
            Tag tag = tagRepo.findById(a.getTagId()).orElse(null);
            if (tag == null) continue;

            TagGroup group = groupRepo.findById(tag.getGroupId()).orElse(null);

            TagBriefVO vo = new TagBriefVO();
            vo.setTagId(tag.getId());
            vo.setTagName(tag.getName());
            vo.setGroupId(tag.getGroupId());
            vo.setGroupName(group != null ? group.getName() : "");
            result.add(vo);
        }
        return result;
    }

    @Override
    public int renameEntityId(String entityType, String oldEntityId, String newEntityId) {
        int updated = assignmentRepo.renameEntityId(entityType, oldEntityId, newEntityId);
        if (updated > 0) {
            log.info("[Tag] 重命名实体引用: entityType={}, {} -> {} (affected={})",
                    entityType, oldEntityId, newEntityId, updated);
        }
        return updated;
    }
}
