package com.lesingle.creation.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lesingle.creation.dto.log.LogQueryDTO;
import com.lesingle.creation.entity.SysLog;
import com.lesingle.creation.common.exception.BusinessException;
import com.lesingle.creation.mapper.SysLogMapper;
import com.lesingle.creation.service.SysLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lesingle.creation.vo.log.LogStatisticsVO;
import com.lesingle.creation.vo.log.LogVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 系统日志服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysLogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> implements SysLogService {

    private final SysLogMapper sysLogMapper;

    @Override
    public Page<LogVO> pageQuery(LogQueryDTO queryDTO, Long tenantId) {
        Page<SysLog> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());

        LambdaQueryWrapper<SysLog> wrapper = new LambdaQueryWrapper<SysLog>()
                .eq(SysLog::getTenantId, tenantId)
                .eq(queryDTO.getUserId() != null, SysLog::getUserId, queryDTO.getUserId())
                .like(queryDTO.getAction() != null, SysLog::getAction, queryDTO.getAction())
                .like(queryDTO.getIp() != null, SysLog::getIp, queryDTO.getIp())
                .like(queryDTO.getKeyword() != null, SysLog::getContent, queryDTO.getKeyword())
                .between(
                        queryDTO.getStartTime() != null && queryDTO.getEndTime() != null,
                        SysLog::getCreateTime,
                        parseDateTime(queryDTO.getStartTime(), LocalTime.MIN),
                        parseDateTime(queryDTO.getEndTime(), LocalTime.MAX)
                )
                .orderByDesc(SysLog::getCreateTime);

        Page<SysLog> resultPage = this.page(page, wrapper);

        List<LogVO> voList = resultPage.getRecords().stream()
                .map(this::convertToVO)
                .toList();

        Page<LogVO> voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
        voPage.setRecords(voList);
        return voPage;
    }

    @Override
    public LogVO getDetail(Long id, Long tenantId) {
        SysLog sysLog = this.getById(id);
        if (sysLog == null || !sysLog.getTenantId().equals(tenantId)) {
            throw new BusinessException("日志记录不存在");
        }
        return convertToVO(sysLog);
    }

    @Override
    public LogStatisticsVO getStatistics(Integer days, Long tenantId) {
        if (days == null) {
            days = 7;
        }

        LogStatisticsVO vo = new LogStatisticsVO();
        vo.setDays(days);

        // 获取统计数据
        Map<String, Object> stats = sysLogMapper.getStatistics(days);
        vo.setTotalCount(((Number) stats.get("total_count")).longValue());
        vo.setRecentCount(((Number) stats.get("recent_count")).longValue());

        // 获取操作类型统计
        List<Map<String, Object>> actionStatsData = sysLogMapper.getActionStats(days);
        List<LogStatisticsVO.ActionStatVO> actionStats = new ArrayList<>();
        for (Map<String, Object> row : actionStatsData) {
            LogStatisticsVO.ActionStatVO stat = new LogStatisticsVO.ActionStatVO();
            stat.setAction((String) row.get("action"));
            stat.setCount(((Number) row.get("count")).longValue());
            actionStats.add(stat);
        }
        vo.setActionStats(actionStats);

        // 获取按天统计
        List<Map<String, Object>> dailyStatsData = sysLogMapper.getDailyStats(days);
        List<LogStatisticsVO.DailyStatVO> dailyStats = new ArrayList<>();
        for (Map<String, Object> row : dailyStatsData) {
            LogStatisticsVO.DailyStatVO stat = new LogStatisticsVO.DailyStatVO();
            stat.setDate(row.get("date").toString());
            stat.setCount(((Number) row.get("count")).longValue());
            dailyStats.add(stat);
        }
        vo.setDailyStats(dailyStats);

        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteByIds(List<Long> ids, Long tenantId) {
        if (ids == null || ids.isEmpty()) {
            return 0;
        }

        // 验证所有日志都属于该租户
        List<SysLog> logs = this.listByIds(ids);
        for (SysLog log : logs) {
            if (!log.getTenantId().equals(tenantId)) {
                throw new BusinessException("无权删除其他租户的日志");
            }
        }

        return this.removeByIds(ids) ? logs.size() : 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int cleanOldLogs(Integer daysToKeep, Long tenantId) {
        if (daysToKeep == null) {
            daysToKeep = 90;
        }

        LocalDateTime cutoffDate = LocalDateTime.now().minusDays(daysToKeep);
        return sysLogMapper.deleteOldLogs(cutoffDate);
    }

    private LogVO convertToVO(SysLog sysLog) {
        LogVO vo = new LogVO();
        vo.setId(sysLog.getId());
        vo.setTenantId(sysLog.getTenantId());
        vo.setUserId(sysLog.getUserId());
        vo.setUsername(sysLog.getUsername());
        vo.setModule(sysLog.getModule());
        vo.setAction(sysLog.getAction());
        vo.setContent(sysLog.getContent());
        vo.setIp(sysLog.getIp());
        vo.setUserAgent(sysLog.getUserAgent());
        vo.setRequestMethod(sysLog.getRequestMethod());
        vo.setRequestUrl(sysLog.getRequestUrl());
        vo.setDuration(sysLog.getDuration());
        vo.setStatus(sysLog.getStatus());
        vo.setErrorMessage(sysLog.getErrorMessage());
        vo.setCreateTime(sysLog.getCreateTime());
        return vo;
    }

    private LocalDateTime parseDateTime(String dateStr, LocalTime defaultTime) {
        if (dateStr == null || dateStr.isEmpty()) {
            return null;
        }
        try {
            LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE);
            return date.atTime(defaultTime);
        } catch (Exception e) {
            log.warn("日期解析失败：{}", dateStr);
            return null;
        }
    }
}
