package com.haha.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haha.common.vo.Result;
import com.haha.entity.DictData;
import com.haha.entity.DictLog;
import com.haha.entity.DictType;
import com.haha.mapper.DictDataMapper;
import com.haha.mapper.DictLogMapper;
import com.haha.mapper.DictTypeMapper;
import com.haha.service.DictService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class DictServiceImpl extends ServiceImpl<DictTypeMapper, DictType> implements DictService {

    private static final String DICT_CACHE_KEY = "dict:data:";
    private static final String DICT_ALL_CACHE_KEY = "dict:data:all";
    private static final long CACHE_EXPIRE_HOURS = 24;

    @Autowired
    private DictTypeMapper dictTypeMapper;

    @Autowired
    private DictDataMapper dictDataMapper;

    @Autowired
    private DictLogMapper dictLogMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public Result<Map<String, Object>> getDictTypeList(Map<String, Object> params) {
        try {
            int page = Integer.parseInt(params.getOrDefault("page", 1).toString());
            int pageSize = Integer.parseInt(params.getOrDefault("pageSize", 10).toString());
            String dictCode = (String) params.get("dictCode");
            String dictName = (String) params.get("dictName");
            Integer status = params.get("status") != null ? Integer.parseInt(params.get("status").toString()) : null;

            LambdaQueryWrapper<DictType> wrapper = new LambdaQueryWrapper<>();
            if (StringUtils.hasText(dictCode)) {
                wrapper.like(DictType::getDictCode, dictCode);
            }
            if (StringUtils.hasText(dictName)) {
                wrapper.like(DictType::getDictName, dictName);
            }
            if (status != null) {
                wrapper.eq(DictType::getStatus, status);
            }
            wrapper.orderByAsc(DictType::getSortOrder);
            wrapper.orderByDesc(DictType::getCreateTime);

            Page<DictType> pageObj = new Page<>(page, pageSize);
            Page<DictType> result = dictTypeMapper.selectPage(pageObj, wrapper);

            Map<String, Object> data = new HashMap<>();
            data.put("list", result.getRecords());
            data.put("total", result.getTotal());
            data.put("pageSize", pageSize);
            data.put("currentPage", page);

            return Result.success("查询成功", data);
        } catch (Exception e) {
            log.error("查询字典类型列表失败", e);
            return Result.error(500, "查询失败: " + e.getMessage());
        }
    }

    @Override
    public Result<DictType> getDictTypeById(Long id) {
        try {
            DictType dictType = dictTypeMapper.selectById(id);
            if (dictType == null) {
                return Result.error(404, "字典类型不存在");
            }
            return Result.success("查询成功", dictType);
        } catch (Exception e) {
            log.error("查询字典类型失败, id={}", id, e);
            return Result.error(500, "查询失败: " + e.getMessage());
        }
    }

    @Override
    public Result<DictType> getDictTypeByCode(String dictCode) {
        try {
            LambdaQueryWrapper<DictType> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DictType::getDictCode, dictCode);
            DictType dictType = dictTypeMapper.selectOne(wrapper);
            if (dictType == null) {
                return Result.error(404, "字典类型不存在");
            }
            return Result.success("查询成功", dictType);
        } catch (Exception e) {
            log.error("查询字典类型失败, dictCode={}", dictCode, e);
            return Result.error(500, "查询失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> addDictType(DictType dictType) {
        try {
            LambdaQueryWrapper<DictType> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DictType::getDictCode, dictType.getDictCode());
            if (dictTypeMapper.selectCount(wrapper) > 0) {
                return Result.error(400, "字典编码已存在");
            }

            dictType.setCreateTime(LocalDateTime.now());
            dictType.setUpdateTime(LocalDateTime.now());
            dictTypeMapper.insert(dictType);

            saveDictLog(dictType, null, "insert", "新增字典类型");

            return Result.success("添加成功");
        } catch (Exception e) {
            log.error("添加字典类型失败", e);
            return Result.error(500, "添加失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> updateDictType(DictType dictType) {
        try {
            DictType oldDictType = dictTypeMapper.selectById(dictType.getId());
            if (oldDictType == null) {
                return Result.error(404, "字典类型不存在");
            }

            dictType.setUpdateTime(LocalDateTime.now());
            dictTypeMapper.updateById(dictType);

            saveDictLog(dictType, oldDictType, "update", "修改字典类型");

            return Result.success("修改成功");
        } catch (Exception e) {
            log.error("修改字典类型失败", e);
            return Result.error(500, "修改失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> deleteDictType(Long id) {
        try {
            DictType dictType = dictTypeMapper.selectById(id);
            if (dictType == null) {
                return Result.error(404, "字典类型不存在");
            }

            if (dictType.getIsSystem() != null && dictType.getIsSystem() == 1) {
                return Result.error(400, "系统内置字典不允许删除");
            }

            dictDataMapper.deleteByDictCode(dictType.getDictCode());
            dictTypeMapper.deleteById(id);

            clearDictCache(dictType.getDictCode());

            saveDictLog(dictType, null, "delete", "删除字典类型");

            return Result.success("删除成功");
        } catch (Exception e) {
            log.error("删除字典类型失败", e);
            return Result.error(500, "删除失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> batchDeleteDictType(List<Long> ids) {
        try {
            for (Long id : ids) {
                DictType dictType = dictTypeMapper.selectById(id);
                if (dictType != null && (dictType.getIsSystem() == null || dictType.getIsSystem() != 1)) {
                    dictDataMapper.deleteByDictCode(dictType.getDictCode());
                    dictTypeMapper.deleteById(id);
                    clearDictCache(dictType.getDictCode());
                }
            }
            return Result.success("批量删除成功");
        } catch (Exception e) {
            log.error("批量删除字典类型失败", e);
            return Result.error(500, "批量删除失败: " + e.getMessage());
        }
    }

    @Override
    public Result<List<DictData>> getDictDataList(String dictCode) {
        try {
            List<DictData> dataList = getDictDataByCode(dictCode);
            return Result.success("查询成功", dataList);
        } catch (Exception e) {
            log.error("查询字典数据列表失败, dictCode={}", dictCode, e);
            return Result.error(500, "查询失败: " + e.getMessage());
        }
    }

    @Override
    public Result<Map<String, Object>> getDictDataPage(Map<String, Object> params) {
        try {
            int page = Integer.parseInt(params.getOrDefault("page", 1).toString());
            int pageSize = Integer.parseInt(params.getOrDefault("pageSize", 10).toString());
            String dictCode = (String) params.get("dictCode");
            String itemLabel = (String) params.get("itemLabel");
            Integer status = params.get("status") != null ? Integer.parseInt(params.get("status").toString()) : null;

            LambdaQueryWrapper<DictData> wrapper = new LambdaQueryWrapper<>();
            if (StringUtils.hasText(dictCode)) {
                wrapper.eq(DictData::getDictCode, dictCode);
            }
            if (StringUtils.hasText(itemLabel)) {
                wrapper.like(DictData::getItemLabel, itemLabel);
            }
            if (status != null) {
                wrapper.eq(DictData::getStatus, status);
            }
            wrapper.orderByAsc(DictData::getSortOrder);
            wrapper.orderByDesc(DictData::getCreateTime);

            Page<DictData> pageObj = new Page<>(page, pageSize);
            Page<DictData> result = dictDataMapper.selectPage(pageObj, wrapper);

            Map<String, Object> data = new HashMap<>();
            data.put("list", result.getRecords());
            data.put("total", result.getTotal());
            data.put("pageSize", pageSize);
            data.put("currentPage", page);

            return Result.success("查询成功", data);
        } catch (Exception e) {
            log.error("查询字典数据列表失败", e);
            return Result.error(500, "查询失败: " + e.getMessage());
        }
    }

    @Override
    public Result<DictData> getDictDataById(Long id) {
        try {
            DictData dictData = dictDataMapper.selectById(id);
            if (dictData == null) {
                return Result.error(404, "字典数据不存在");
            }
            return Result.success("查询成功", dictData);
        } catch (Exception e) {
            log.error("查询字典数据失败, id={}", id, e);
            return Result.error(500, "查询失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> addDictData(DictData dictData) {
        try {
            LambdaQueryWrapper<DictData> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DictData::getDictCode, dictData.getDictCode());
            wrapper.eq(DictData::getItemValue, dictData.getItemValue());
            if (dictDataMapper.selectCount(wrapper) > 0) {
                return Result.error(400, "该字典下已存在相同的字典项值");
            }

            dictData.setCreateTime(LocalDateTime.now());
            dictData.setUpdateTime(LocalDateTime.now());
            dictDataMapper.insert(dictData);

            clearDictCache(dictData.getDictCode());

            return Result.success("添加成功");
        } catch (Exception e) {
            log.error("添加字典数据失败", e);
            return Result.error(500, "添加失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> updateDictData(DictData dictData) {
        try {
            DictData oldDictData = dictDataMapper.selectById(dictData.getId());
            if (oldDictData == null) {
                return Result.error(404, "字典数据不存在");
            }

            if (!oldDictData.getItemValue().equals(dictData.getItemValue())) {
                LambdaQueryWrapper<DictData> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(DictData::getDictCode, oldDictData.getDictCode());
                wrapper.eq(DictData::getItemValue, dictData.getItemValue());
                wrapper.ne(DictData::getId, dictData.getId());
                if (dictDataMapper.selectCount(wrapper) > 0) {
                    return Result.error(400, "该字典下已存在相同的字典项值");
                }
            }

            dictData.setUpdateTime(LocalDateTime.now());
            dictDataMapper.updateById(dictData);

            clearDictCache(oldDictData.getDictCode());

            return Result.success("修改成功");
        } catch (Exception e) {
            log.error("修改字典数据失败", e);
            return Result.error(500, "修改失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> deleteDictData(Long id) {
        try {
            DictData dictData = dictDataMapper.selectById(id);
            if (dictData == null) {
                return Result.error(404, "字典数据不存在");
            }

            dictDataMapper.deleteById(id);

            clearDictCache(dictData.getDictCode());

            return Result.success("删除成功");
        } catch (Exception e) {
            log.error("删除字典数据失败", e);
            return Result.error(500, "删除失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> batchDeleteDictData(List<Long> ids) {
        try {
            Set<String> dictCodes = new HashSet<>();
            for (Long id : ids) {
                DictData dictData = dictDataMapper.selectById(id);
                if (dictData != null) {
                    dictCodes.add(dictData.getDictCode());
                    dictDataMapper.deleteById(id);
                }
            }

            for (String dictCode : dictCodes) {
                clearDictCache(dictCode);
            }

            return Result.success("批量删除成功");
        } catch (Exception e) {
            log.error("批量删除字典数据失败", e);
            return Result.error(500, "批量删除失败: " + e.getMessage());
        }
    }

    @Override
    public Map<String, List<DictData>> getAllDictData() {
        try {
            String cachedJson = redisTemplate.opsForValue().get(DICT_ALL_CACHE_KEY);
            if (cachedJson != null) {
                return JSON.parseObject(cachedJson, Map.class);
            }

            LambdaQueryWrapper<DictType> typeWrapper = new LambdaQueryWrapper<>();
            typeWrapper.eq(DictType::getStatus, 1);
            typeWrapper.orderByAsc(DictType::getSortOrder);
            List<DictType> dictTypes = dictTypeMapper.selectList(typeWrapper);

            Map<String, List<DictData>> cachedData = new LinkedHashMap<>();

            for (DictType dictType : dictTypes) {
                List<DictData> dataList = getDictDataByCode(dictType.getDictCode());
                cachedData.put(dictType.getDictCode(), dataList);
            }

            redisTemplate.opsForValue().set(DICT_ALL_CACHE_KEY, JSON.toJSONString(cachedData), CACHE_EXPIRE_HOURS, TimeUnit.HOURS);

            return cachedData;
        } catch (Exception e) {
            log.error("获取所有字典数据失败", e);
            return new HashMap<>();
        }
    }

    @Override
    public List<DictData> getDictDataByCode(String dictCode) {
        try {
            String cacheKey = DICT_CACHE_KEY + dictCode;
            String cachedJson = redisTemplate.opsForValue().get(cacheKey);
            if (cachedJson != null) {
                return JSON.parseArray(cachedJson, DictData.class);
            }

            List<DictData> dataList = dictDataMapper.selectByDictCode(dictCode);

            redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(dataList), CACHE_EXPIRE_HOURS, TimeUnit.HOURS);

            return dataList;
        } catch (Exception e) {
            log.error("获取字典数据失败, dictCode={}", dictCode, e);
            return new ArrayList<>();
        }
    }

    @Override
    public void refreshCache() {
        try {
            Set<String> keys = redisTemplate.keys(DICT_CACHE_KEY + "*");
            if (keys != null && !keys.isEmpty()) {
                redisTemplate.delete(keys);
            }
            if (Boolean.TRUE.equals(redisTemplate.hasKey(DICT_ALL_CACHE_KEY))) {
                redisTemplate.delete(DICT_ALL_CACHE_KEY);
            }
            log.info("字典缓存已刷新");
        } catch (Exception e) {
            log.error("刷新字典缓存失败", e);
        }
    }

    @Override
    public String getDictLabel(String dictCode, String itemValue) {
        if (!StringUtils.hasText(dictCode) || !StringUtils.hasText(itemValue)) {
            return "";
        }
        List<DictData> dataList = getDictDataByCode(dictCode);
        for (DictData data : dataList) {
            if (itemValue.equals(data.getItemValue())) {
                return data.getItemLabel();
            }
        }
        return "";
    }

    @Override
    public String getDictValue(String dictCode, String itemLabel) {
        if (!StringUtils.hasText(dictCode) || !StringUtils.hasText(itemLabel)) {
            return "";
        }
        List<DictData> dataList = getDictDataByCode(dictCode);
        for (DictData data : dataList) {
            if (itemLabel.equals(data.getItemLabel())) {
                return data.getItemValue();
            }
        }
        return "";
    }

    @Override
    public Result<Void> exportDictData(String dictCode) {
        return Result.success("导出成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> importDictData(List<DictData> dataList) {
        try {
            if (dataList == null || dataList.isEmpty()) {
                return Result.error(400, "导入数据不能为空");
            }

            Set<String> dictCodes = new HashSet<>();
            for (DictData data : dataList) {
                data.setCreateTime(LocalDateTime.now());
                data.setUpdateTime(LocalDateTime.now());
                dictDataMapper.insert(data);
                dictCodes.add(data.getDictCode());
            }

            for (String code : dictCodes) {
                clearDictCache(code);
            }

            return Result.success("导入成功");
        } catch (Exception e) {
            log.error("导入字典数据失败", e);
            return Result.error(500, "导入失败: " + e.getMessage());
        }
    }

    private void clearDictCache(String dictCode) {
        try {
            String cacheKey = DICT_CACHE_KEY + dictCode;
            redisTemplate.delete(cacheKey);
            redisTemplate.delete(DICT_ALL_CACHE_KEY);
        } catch (Exception e) {
            log.error("清除字典缓存失败, dictCode={}", dictCode, e);
        }
    }

    private void saveDictLog(DictType dictType, DictType oldDictType, String operationType, String operationDesc) {
        try {
            DictLog log = new DictLog();
            log.setDictCode(dictType.getDictCode());
            log.setDictName(dictType.getDictName());
            log.setOperationType(operationType);
            log.setOperationDesc(operationDesc);
            log.setBeforeData(oldDictType != null ? JSON.toJSONString(oldDictType) : null);
            log.setAfterData(JSON.toJSONString(dictType));
            log.setCreateTime(LocalDateTime.now());
            dictLogMapper.insert(log);
        } catch (Exception e) {
            log.error("保存字典日志失败", e);
        }
    }
}
