package research.loghunter.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import research.loghunter.entity.ErrorLog;

import java.time.LocalDateTime;
import java.util.List;

public interface ErrorLogRepository extends JpaRepository<ErrorLog, Long> {
    
    List<ErrorLog> findByServerIdOrderByOccurredAtDesc(Long serverId);
    
    Page<ErrorLog> findByServerIdOrderByOccurredAtDesc(Long serverId, Pageable pageable);
    
    @Query("SELECT e FROM ErrorLog e WHERE " +
           "(:serverId IS NULL OR e.server.id = :serverId) AND " +
           "(:patternId IS NULL OR e.pattern.id = :patternId) AND " +
           "(:severity IS NULL OR e.severity = :severity) AND " +
           "(:filePath IS NULL OR e.filePath = :filePath) AND " +
           "(:startDate IS NULL OR e.occurredAt >= :startDate) AND " +
           "(:endDate IS NULL OR e.occurredAt <= :endDate) AND " +
           "(:keyword IS NULL OR LOWER(e.summary) LIKE LOWER(CONCAT('%', :keyword, '%')) OR LOWER(e.context) LIKE LOWER(CONCAT('%', :keyword, '%'))) " +
           "ORDER BY e.occurredAt DESC")
    Page<ErrorLog> searchErrors(
            @Param("serverId") Long serverId,
            @Param("patternId") Long patternId,
            @Param("severity") String severity,
            @Param("filePath") String filePath,
            @Param("startDate") LocalDateTime startDate,
            @Param("endDate") LocalDateTime endDate,
            @Param("keyword") String keyword,
            Pageable pageable);

    // 서버별 삭제
    void deleteByServerId(Long serverId);
    
    // 서버별 에러 수
    long countByServerId(Long serverId);

    // 전체 파일 경로 목록 (중복 제거)
    @Query("SELECT DISTINCT e.filePath FROM ErrorLog e ORDER BY e.filePath")
    List<String> findDistinctFilePaths();

    // 서버별 파일 경로 목록 (중복 제거)
    @Query("SELECT DISTINCT e.filePath FROM ErrorLog e WHERE e.server.id = :serverId ORDER BY e.filePath")
    List<String> findDistinctFilePathsByServerId(@Param("serverId") Long serverId);

    // ID 목록으로 삭제
    @Modifying
    @Query("DELETE FROM ErrorLog e WHERE e.id IN :ids")
    int deleteByIdIn(@Param("ids") List<Long> ids);

    // 서버+파일 기준 삭제
    @Modifying
    @Query("DELETE FROM ErrorLog e WHERE e.server.id = :serverId AND e.filePath = :filePath")
    int deleteByServerIdAndFilePath(@Param("serverId") Long serverId, @Param("filePath") String filePath);

    // 파일별 에러 통계
    @Query("SELECT e.filePath, e.server.name, COUNT(e), " +
           "SUM(CASE WHEN e.severity = 'CRITICAL' THEN 1 ELSE 0 END), " +
           "SUM(CASE WHEN e.severity = 'ERROR' THEN 1 ELSE 0 END), " +
           "SUM(CASE WHEN e.severity = 'WARN' THEN 1 ELSE 0 END), " +
           "MAX(e.occurredAt) " +
           "FROM ErrorLog e " +
           "WHERE (:serverId IS NULL OR e.server.id = :serverId) " +
           "GROUP BY e.filePath, e.server.name " +
           "ORDER BY COUNT(e) DESC")
    List<Object[]> getErrorStatsByFile(@Param("serverId") Long serverId);

    // 서버별 에러 통계
    @Query("SELECT e.server.id, e.server.name, COUNT(e), " +
           "SUM(CASE WHEN e.severity = 'CRITICAL' THEN 1 ELSE 0 END), " +
           "SUM(CASE WHEN e.severity = 'ERROR' THEN 1 ELSE 0 END), " +
           "SUM(CASE WHEN e.severity = 'WARN' THEN 1 ELSE 0 END), " +
           "MAX(e.occurredAt) " +
           "FROM ErrorLog e " +
           "GROUP BY e.server.id, e.server.name " +
           "ORDER BY COUNT(e) DESC")
    List<Object[]> getErrorStatsByServer();

    // 패턴별 에러 통계
    @Query("SELECT e.pattern.id, e.pattern.name, e.pattern.severity, COUNT(e), MAX(e.occurredAt) " +
           "FROM ErrorLog e " +
           "WHERE (:serverId IS NULL OR e.server.id = :serverId) " +
           "GROUP BY e.pattern.id, e.pattern.name, e.pattern.severity " +
           "ORDER BY COUNT(e) DESC")
    List<Object[]> getErrorStatsByPattern(@Param("serverId") Long serverId);

    // 트리용 파일별 에러 통계 (서버ID, 서버명, 파일경로, 에러수, CRITICAL, ERROR, WARN)
    @Query("SELECT e.server.id, e.server.name, e.filePath, COUNT(e), " +
           "SUM(CASE WHEN e.severity = 'CRITICAL' THEN 1 ELSE 0 END), " +
           "SUM(CASE WHEN e.severity = 'ERROR' THEN 1 ELSE 0 END), " +
           "SUM(CASE WHEN e.severity = 'WARN' THEN 1 ELSE 0 END) " +
           "FROM ErrorLog e " +
           "GROUP BY e.server.id, e.server.name, e.filePath " +
           "ORDER BY e.server.name, e.filePath")
    List<Object[]> getFileErrorStats();

    // 서버별 일별 에러 통계 (대시보드, 월별현황용) - SQLite 네이티브 쿼리 (epoch ms 지원)
    @Query(value = "SELECT e.server_id, s.name, date(e.occurred_at/1000, 'unixepoch', 'localtime'), COUNT(*), " +
           "SUM(CASE WHEN e.severity = 'CRITICAL' THEN 1 ELSE 0 END), " +
           "SUM(CASE WHEN e.severity = 'ERROR' THEN 1 ELSE 0 END), " +
           "SUM(CASE WHEN e.severity = 'WARN' THEN 1 ELSE 0 END) " +
           "FROM error_logs e JOIN servers s ON e.server_id = s.id " +
           "WHERE e.occurred_at >= :startMs AND e.occurred_at < :endMs " +
           "GROUP BY e.server_id, s.name, date(e.occurred_at/1000, 'unixepoch', 'localtime') " +
           "ORDER BY e.server_id, date(e.occurred_at/1000, 'unixepoch', 'localtime')", nativeQuery = true)
    List<Object[]> getDailyStatsByServer(@Param("startMs") long startMs, 
                                          @Param("endMs") long endMs);

    // 서버별 시간대별 에러 통계 (일별현황용 - 원본 데이터, 5분 단위는 서비스에서 처리)
    @Query("SELECT e.server.id, e.server.name, e.occurredAt, e.severity " +
           "FROM ErrorLog e " +
           "WHERE e.occurredAt >= :startDate AND e.occurredAt < :endDate " +
           "ORDER BY e.server.id, e.occurredAt")
    List<Object[]> getErrorsByDateRange(@Param("startDate") LocalDateTime startDate, 
                                         @Param("endDate") LocalDateTime endDate);
}
