/**
 * @ProjectName: 智慧评标-主观分助手
 * @Package: com.zhpb.gdyd_zhpb_zgf.controller
 * @ClassName: SysLogController
 * @Description: 系统日志查询接口
 * @Author: 张志锋
 * @Date: 2025-11-24
 * @Version: 1.0
 */
package com.zhpb.gdyd_zhpb_zgf.controller;

import com.zhpb.gdyd_zhpb_zgf.entity.mysql.SysLog;
import com.zhpb.gdyd_zhpb_zgf.repository.mysql.SysLogRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import jakarta.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;

/**
 * 系统日志查询接口
 */
@RestController
@RequestMapping("/api/logs")
@Tag(name = "系统日志", description = "系统日志查询接口")
public class SysLogController {

    private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_DATE_TIME;
    private static final DateTimeFormatter NORMAL_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final List<String> KNOWN_LEVELS = Arrays.asList("ERROR", "WARN", "INFO", "DEBUG", "TRACE", "OUT");

    @Autowired
    private SysLogRepository sysLogRepository;

    @GetMapping
    @Operation(summary = "分页查询日志", description = "支持按级别、关键字、时间范围筛选日志")
    public Map<String, Object> queryLogs(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size,
            @RequestParam(required = false) String level,
            @RequestParam(required = false) String keyword,
            @RequestParam(required = false) String startTime,
            @RequestParam(required = false) String endTime) {

        int safePage = Math.max(page, 0);
        int safeSize = Math.min(Math.max(size, 1), 200);

        Pageable pageable = PageRequest.of(safePage, safeSize, Sort.by(Sort.Direction.DESC, "createTime"));
        Specification<SysLog> specification = buildSpecification(level, keyword, startTime, endTime);

        Page<SysLog> pageData = sysLogRepository.findAll(specification, pageable);

        Map<String, Object> response = new HashMap<>();
        response.put("content", pageData.getContent());
        response.put("totalElements", pageData.getTotalElements());
        response.put("totalPages", pageData.getTotalPages());
        response.put("page", pageData.getNumber());
        response.put("size", pageData.getSize());
        return response;
    }

    @GetMapping("/stats")
    @Operation(summary = "日志统计信息", description = "返回日志数量、各级别分布等统计数据")
    public Map<String, Object> logStats() {
        Map<String, Object> result = new HashMap<>();
        long total = sysLogRepository.count();
        result.put("total", total);

        LocalDateTime last24h = LocalDateTime.now().minusHours(24);
        long last24hCount = sysLogRepository.count((root, query, cb) ->
                cb.greaterThanOrEqualTo(root.get("createTime"), last24h));
        result.put("last24Hours", last24hCount);

        Map<String, Long> levelStats = new LinkedHashMap<>();
        for (String lvl : KNOWN_LEVELS) {
            long count = sysLogRepository.count((root, query, cb) ->
                    cb.equal(cb.upper(root.get("logLevel")), lvl));
            levelStats.put(lvl, count);
        }
        result.put("levelStats", levelStats);

        SysLog latest = sysLogRepository.findTopByOrderByCreateTimeDesc();
        result.put("latest", latest);
        return result;
    }

    private Specification<SysLog> buildSpecification(String level, String keyword,
                                                     String startTime, String endTime) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (StringUtils.hasText(level) && !"ALL".equalsIgnoreCase(level)) {
                predicates.add(cb.equal(cb.upper(root.get("logLevel")), level.trim().toUpperCase()));
            }

            if (StringUtils.hasText(keyword)) {
                String likeValue = "%" + keyword.trim().toLowerCase() + "%";
                predicates.add(cb.or(
                        cb.like(cb.lower(root.get("logContent")), likeValue),
                        cb.like(cb.lower(root.get("fullMessage")), likeValue),
                        cb.like(cb.lower(root.get("loggerName")), likeValue),
                        cb.like(cb.lower(root.get("threadName")), likeValue)
                ));
            }

            LocalDateTime start = parseDateTime(startTime);
            LocalDateTime end = parseDateTime(endTime);
            if (start != null) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("createTime"), start));
            }
            if (end != null) {
                predicates.add(cb.lessThanOrEqualTo(root.get("createTime"), end));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }

    private LocalDateTime parseDateTime(String raw) {
        if (!StringUtils.hasText(raw)) {
            return null;
        }
        String value = raw.trim();
        // datetime-local 会带 T
        if (value.contains("T") && !value.contains("Z")) {
            value = value.replace("T", " ");
        }
        List<DateTimeFormatter> formatters = Arrays.asList(ISO_FORMATTER, NORMAL_FORMATTER,
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        for (DateTimeFormatter formatter : formatters) {
            try {
                return LocalDateTime.parse(value, formatter);
            } catch (DateTimeParseException ignored) {
            }
        }
        return null;
    }
}

