package com.lesingle.modules.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lesingle.common.enums.ErrorCode;
import com.lesingle.common.exception.BusinessException;
import com.lesingle.common.result.PageResult;
import com.lesingle.modules.sys.dto.QueryLogDto;
import com.lesingle.modules.sys.entity.SysLog;
import com.lesingle.modules.sys.entity.SysUser;
import com.lesingle.modules.sys.mapper.SysLogMapper;
import com.lesingle.modules.sys.mapper.SysUserMapper;
import com.lesingle.modules.sys.service.ISysLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> implements ISysLogService {

    private final SysUserMapper userMapper;

    @Override
    public PageResult<Map<String, Object>> findAll(QueryLogDto dto) {
        LambdaQueryWrapper<SysLog> wrapper = new LambdaQueryWrapper<SysLog>()
                .orderByDesc(SysLog::getCreateTime);

        if (dto.getUserId() != null) wrapper.eq(SysLog::getUserId, dto.getUserId());
        if (dto.getAction() != null) wrapper.like(SysLog::getAction, dto.getAction());
        if (dto.getIp() != null) wrapper.eq(SysLog::getIp, dto.getIp());

        if (dto.getKeyword() != null && !dto.getKeyword().isBlank()) {
            wrapper.and(w -> w.like(SysLog::getAction, dto.getKeyword()).or().like(SysLog::getContent, dto.getKeyword()));
        }

        if (dto.getStartTime() != null) {
            wrapper.ge(SysLog::getCreateTime, LocalDateTime.parse(dto.getStartTime(), DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        }
        if (dto.getEndTime() != null) {
            wrapper.le(SysLog::getCreateTime, LocalDateTime.parse(dto.getEndTime(), DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        }

        IPage<SysLog> result = baseMapper.selectPage(new Page<>(dto.getPage(), dto.getPageSize()), wrapper);

        // 附加用户信息
        List<Map<String, Object>> list = new ArrayList<>();
        for (SysLog logEntry : result.getRecords()) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("id", logEntry.getId());
            map.put("userId", logEntry.getUserId());
            map.put("action", logEntry.getAction());
            map.put("content", logEntry.getContent());
            map.put("ip", logEntry.getIp());
            map.put("userAgent", logEntry.getUserAgent());
            map.put("createTime", logEntry.getCreateTime());

            if (logEntry.getUserId() != null) {
                SysUser user = userMapper.selectById(logEntry.getUserId());
                if (user != null) {
                    map.put("user", Map.of("id", user.getId(), "username", user.getUsername(), "nickname", user.getNickname()));
                }
            }
            list.add(map);
        }

        return new PageResult<>(list, result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public Map<String, Object> getStatistics(Integer days) {
        if (days == null) days = 7;
        LocalDateTime since = LocalDateTime.now().minusDays(days);

        long totalCount = count();
        long recentCount = count(new LambdaQueryWrapper<SysLog>().ge(SysLog::getCreateTime, since));

        List<Map<String, Object>> actionStats = baseMapper.selectActionStats(since);
        List<Map<String, Object>> dailyStats = baseMapper.selectDailyStats(since);

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("totalCount", totalCount);
        result.put("recentCount", recentCount);
        result.put("days", days);
        result.put("actionStats", actionStats);
        result.put("dailyStats", dailyStats);
        return result;
    }

    @Override
    public Map<String, Object> findDetail(Long id) {
        SysLog logEntry = getById(id);
        if (logEntry == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "日志不存在");
        }

        Map<String, Object> map = new LinkedHashMap<>();
        map.put("id", logEntry.getId());
        map.put("userId", logEntry.getUserId());
        map.put("action", logEntry.getAction());
        map.put("content", logEntry.getContent());
        map.put("ip", logEntry.getIp());
        map.put("userAgent", logEntry.getUserAgent());
        map.put("createTime", logEntry.getCreateTime());

        if (logEntry.getUserId() != null) {
            SysUser user = userMapper.selectById(logEntry.getUserId());
            if (user != null) {
                map.put("user", Map.of("id", user.getId(), "username", user.getUsername(), "nickname", user.getNickname()));
            }
        }
        return map;
    }

    @Override
    public void batchDelete(List<Long> ids) {
        log.info("批量删除日志，数量：{}", ids.size());
        removeByIds(ids);
    }

    @Override
    public Map<String, Object> cleanOldLogs(Integer daysToKeep) {
        if (daysToKeep == null) daysToKeep = 90;
        LocalDateTime cutoff = LocalDateTime.now().minusDays(daysToKeep);

        long deleted = baseMapper.delete(new LambdaQueryWrapper<SysLog>().lt(SysLog::getCreateTime, cutoff));
        log.info("清理旧日志，保留天数：{}，删除数量：{}", daysToKeep, deleted);

        return Map.of("deleted", deleted, "cutoffDate", cutoff.toString());
    }
}
