package com.ycwl.basic.puzzle.service.impl;
import cn.hutool.core.util.StrUtil;
import com.ycwl.basic.puzzle.util.ElementConfigHelper;

import cn.hutool.core.bean.BeanUtil;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.puzzle.dto.ElementCreateRequest;
import com.ycwl.basic.puzzle.dto.PuzzleElementDTO;
import com.ycwl.basic.puzzle.dto.PuzzleTemplateDTO;
import com.ycwl.basic.puzzle.dto.TemplateCreateRequest;
import com.ycwl.basic.puzzle.entity.PuzzleElementEntity;
import com.ycwl.basic.puzzle.entity.PuzzleTemplateEntity;
import com.ycwl.basic.puzzle.mapper.PuzzleElementMapper;
import com.ycwl.basic.puzzle.mapper.PuzzleTemplateMapper;
import com.ycwl.basic.puzzle.repository.PuzzleRepository;
import com.ycwl.basic.puzzle.service.IPuzzleTemplateService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 拼图模板管理服务实现
 *
 * @author Claude
 * @since 2025-01-17
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PuzzleTemplateServiceImpl implements IPuzzleTemplateService {

    private final PuzzleTemplateMapper templateMapper;
    private final PuzzleElementMapper elementMapper;
    private final PuzzleRepository puzzleRepository;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createTemplate(TemplateCreateRequest request) {
        log.info("创建拼图模板: code={}, name={}", request.getCode(), request.getName());

        // 检查编码是否已存在
        int count = templateMapper.countByCode(request.getCode(), null);
        if (count > 0) {
            throw new IllegalArgumentException("模板编码已存在: " + request.getCode());
        }

        // 转换为实体并插入
        PuzzleTemplateEntity entity = BeanUtil.copyProperties(request, PuzzleTemplateEntity.class);
        entity.setDeleted(0);
        templateMapper.insert(entity);

        // 清除景区模板列表缓存
        if (entity.getScenicId() != null) {
            puzzleRepository.clearTemplateByScenicCache(entity.getScenicId());
        }

        log.info("拼图模板创建成功: id={}, code={}", entity.getId(), entity.getCode());
        return entity.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTemplate(Long id, TemplateCreateRequest request) {
        log.info("更新拼图模板: id={}", id);

        // 检查模板是否存在
        PuzzleTemplateEntity existing = templateMapper.getById(id);
        if (existing == null) {
            throw new IllegalArgumentException("模板不存在: " + id);
        }

        // 记录旧值
        String oldCode = existing.getCode();
        Long oldScenicId = existing.getScenicId();

        // 如果修改了编码，检查新编码是否已存在
        if (request.getCode() != null && !request.getCode().equals(existing.getCode())) {
            int count = templateMapper.countByCode(request.getCode(), id);
            if (count > 0) {
                throw new IllegalArgumentException("模板编码已存在: " + request.getCode());
            }
        }

        // 更新
        PuzzleTemplateEntity entity = BeanUtil.copyProperties(request, PuzzleTemplateEntity.class);
        entity.setId(id);
        templateMapper.update(entity);

        // 清除缓存
        puzzleRepository.clearTemplateCache(id, oldCode);
        if (request.getCode() != null && !request.getCode().equals(oldCode)) {
            puzzleRepository.clearTemplateCache(null, request.getCode());
        }

        // 如果 scenicId 变更，清除新旧两个景区的缓存
        Long newScenicId = request.getScenicId();
        if (newScenicId != null && !newScenicId.equals(oldScenicId)) {
            puzzleRepository.clearTemplateByScenicCache(newScenicId);
        }

        log.info("拼图模板更新成功: id={}", id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTemplate(Long id) {
        log.info("删除拼图模板: id={}", id);

        // 检查模板是否存在
        PuzzleTemplateEntity existing = templateMapper.getById(id);
        if (existing == null) {
            throw new IllegalArgumentException("模板不存在: " + id);
        }

        // 删除模板及其所有元素
        templateMapper.deleteById(id);
        elementMapper.deleteByTemplateId(id);

        // 清除缓存
        puzzleRepository.clearTemplateCache(id, existing.getCode());

        log.info("拼图模板删除成功: id={}, 同时删除了关联的元素", id);
    }

    @Override
    public PuzzleTemplateDTO getTemplateDetail(Long id) {
        log.debug("获取拼图模板详情: id={}", id);

        PuzzleTemplateEntity template = templateMapper.getById(id);
        if (template == null) {
            throw new IllegalArgumentException("模板不存在: " + id);
        }

        return convertToDTO(template);
    }

    @Override
    public PuzzleTemplateDTO getTemplateByCode(String code) {
        log.debug("根据编码获取拼图模板: code={}", code);

        PuzzleTemplateEntity template = templateMapper.getByCode(code);
        if (template == null) {
            throw new IllegalArgumentException("模板不存在: " + code);
        }

        return convertToDTO(template);
    }

    @Override
    public List<PuzzleTemplateDTO> listTemplates(Long scenicId, String category, Integer status) {
        log.debug("查询拼图模板列表: scenicId={}, category={}, status={}", scenicId, category, status);

        List<PuzzleTemplateEntity> templates = templateMapper.list(scenicId, category, status);
        return templates.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public PageResponse<PuzzleTemplateDTO> pageTemplates(Integer page, Integer pageSize,
                                                          Long scenicId, String category, Integer status) {
        log.debug("分页查询拼图模板: page={}, pageSize={}, scenicId={}, category={}, status={}",
                page, pageSize, scenicId, category, status);

        // 参数校验
        if (page == null || page < 1) {
            page = 1;
        }
        if (pageSize == null || pageSize < 1) {
            pageSize = 10;
        }
        if (pageSize > 100) {
            pageSize = 100; // 限制最大页面大小
        }

        // 使用PageHelper进行分页
        com.github.pagehelper.Page<PuzzleTemplateEntity> pageResult =
                com.github.pagehelper.PageHelper.startPage(page, pageSize)
                        .doSelectPage(() -> templateMapper.list(scenicId, category, status));

        // 转换为DTO
        List<PuzzleTemplateDTO> dtoList = pageResult.getResult().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());

        // 构建分页响应
        PageResponse<PuzzleTemplateDTO> response = new PageResponse<>();
        response.setList(dtoList);
        response.setTotal((int) pageResult.getTotal());
        response.setPage(page);
        response.setPageSize(pageSize);

        log.debug("分页查询完成: total={}, currentSize={}", pageResult.getTotal(), dtoList.size());
        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addElement(ElementCreateRequest request) {
        log.info("添加元素到模板: templateId={}, elementKey={}", request.getTemplateId(), request.getElementKey());

        // 1. 验证请求
        ElementConfigHelper.validateRequest(request);

        // 2. 检查模板是否存在
        PuzzleTemplateEntity template = templateMapper.getById(request.getTemplateId());
        if (template == null) {
            throw new IllegalArgumentException("模板不存在: " + request.getTemplateId());
        }

        // 3. 转换为Entity（使用Helper）
        PuzzleElementEntity entity = ElementConfigHelper.toEntity(request);
        entity.setDeleted(0);

        // 4. 插入数据库
        elementMapper.insert(entity);

        // 5. 清除元素缓存
        puzzleRepository.clearElementsCache(request.getTemplateId());

        log.info("元素添加成功: id={}, type={}, key={}",
            entity.getId(), entity.getElementType(), entity.getElementKey());
        return entity.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAddElements(Long templateId, List<ElementCreateRequest> elements) {
        log.info("批量添加元素到模板: templateId={}, count={}", templateId, elements.size());

        // 1. 校验模板
        PuzzleTemplateEntity template = templateMapper.getById(templateId);
        if (template == null) {
            throw new IllegalArgumentException("模板不存在: " + templateId);
        }

        // 2. 批量转换
        List<PuzzleElementEntity> entityList = elements.stream()
                .peek(req -> {
                    req.setTemplateId(templateId);
                    ElementConfigHelper.validateRequest(req);
                })
                .map(ElementConfigHelper::toEntity)
                .peek(entity -> entity.setDeleted(0))
                .collect(Collectors.toList());

        // 3. 批量插入
        if (!entityList.isEmpty()) {
            elementMapper.batchInsert(entityList);
            // 4. 清除元素缓存
            puzzleRepository.clearElementsCache(templateId);
            log.info("批量添加元素成功: templateId={}, count={}", templateId, entityList.size());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void replaceElements(Long templateId, List<ElementCreateRequest> elements) {
        log.info("批量替换元素: templateId={}, count={}", templateId, elements.size());

        // 1. 校验模板
        PuzzleTemplateEntity template = templateMapper.getById(templateId);
        if (template == null) {
            throw new IllegalArgumentException("模板不存在: " + templateId);
        }

        // 2. 获取现有元素（建立 elementKey -> Entity 的映射）
        List<PuzzleElementEntity> existingElements = elementMapper.getByTemplateId(templateId);
        Map<String, PuzzleElementEntity> existingMap = existingElements.stream()
                .collect(Collectors.toMap(
                    PuzzleElementEntity::getElementKey,
                    entity -> entity,
                    (e1, e2) -> e1  // 如果有重复key，保留第一个
                ));

        // 3. 构建新元素的 key 集合
        Set<String> newElementKeys = elements.stream()
                .map(ElementCreateRequest::getElementKey)
                .collect(Collectors.toSet());

        // 4. 找出需要删除的元素（旧元素中不在新元素列表中的）
        List<Long> toDeleteIds = existingElements.stream()
                .filter(entity -> !newElementKeys.contains(entity.getElementKey()))
                .map(PuzzleElementEntity::getId)
                .collect(Collectors.toList());

        // 5. 删除不需要的元素
        int deletedCount = 0;
        for (Long id : toDeleteIds) {
            elementMapper.deleteById(id);
            deletedCount++;
        }
        log.info("删除不需要的元素: templateId={}, count={}", templateId, deletedCount);

        // 6. 处理新元素列表：更新或插入
        int updatedCount = 0;
        int insertedCount = 0;
        for (ElementCreateRequest request : elements) {
            request.setTemplateId(templateId);
            ElementConfigHelper.validateRequest(request);

            PuzzleElementEntity existingEntity = existingMap.get(request.getElementKey());
            if (existingEntity != null) {
                // 更新现有元素
                PuzzleElementEntity entity = ElementConfigHelper.toEntity(request);
                entity.setId(existingEntity.getId());
                elementMapper.update(entity);
                updatedCount++;
            } else {
                // 插入新元素
                PuzzleElementEntity entity = ElementConfigHelper.toEntity(request);
                entity.setDeleted(0);
                elementMapper.insert(entity);
                insertedCount++;
            }
        }

        log.info("批量替换元素完成: templateId={}, deleted={}, updated={}, inserted={}",
            templateId, deletedCount, updatedCount, insertedCount);

        // 7. 清除元素缓存
        puzzleRepository.clearElementsCache(templateId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateElement(Long id, ElementCreateRequest request) {
        log.info("更新元素: id={}", id);

        // 1. 校验元素存在
        PuzzleElementEntity existing = elementMapper.getById(id);
        if (existing == null) {
            throw new IllegalArgumentException("元素不存在: " + id);
        }

        // 2. 验证请求
        ElementConfigHelper.validateRequest(request);

        // 3. 转换并更新
        PuzzleElementEntity entity = ElementConfigHelper.toEntity(request);
        entity.setId(id);
        elementMapper.update(entity);

        // 4. 清除元素缓存
        puzzleRepository.clearElementsCache(existing.getTemplateId());

        log.info("元素更新成功: id={}", id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteElement(Long id) {
        log.info("删除元素: id={}", id);

        // 检查元素是否存在
        PuzzleElementEntity existing = elementMapper.getById(id);
        if (existing == null) {
            throw new IllegalArgumentException("元素不存在: " + id);
        }

        elementMapper.deleteById(id);

        // 清除元素缓存
        puzzleRepository.clearElementsCache(existing.getTemplateId());

        log.info("元素删除成功: id={}", id);
    }

    @Override
    public PuzzleElementDTO getElementDetail(Long id) {
        log.debug("获取元素详情: id={}", id);

        PuzzleElementEntity element = elementMapper.getById(id);
        if (element == null) {
            throw new IllegalArgumentException("元素不存在: " + id);
        }

        return convertElementToDTO(element);
    }

    /**
     * 转换为DTO（包含元素列表）
     */
    private PuzzleTemplateDTO convertToDTO(PuzzleTemplateEntity template) {
        PuzzleTemplateDTO dto = BeanUtil.copyProperties(template, PuzzleTemplateDTO.class);

        // 查询元素列表
        List<PuzzleElementEntity> elements = elementMapper.getByTemplateId(template.getId());
        List<PuzzleElementDTO> elementDTOs = elements.stream()
                .map(this::convertElementToDTO)
                .collect(Collectors.toList());
        dto.setElements(elementDTOs);

        return dto;
    }

    /**
     * 转换元素为DTO
     */
    private PuzzleElementDTO convertElementToDTO(PuzzleElementEntity entity) {
        PuzzleElementDTO dto = new PuzzleElementDTO();
        BeanUtil.copyProperties(entity, dto);

        // 解析config为configMap（方便前端使用）
        if (StrUtil.isNotBlank(entity.getConfig())) {
            dto.setConfigMap(ElementConfigHelper.parseConfigToMap(entity.getConfig()));
        }

        return dto;
    }
}
