package research.loghunter.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import research.loghunter.dto.ErrorLogDto;
import research.loghunter.entity.Server;
import research.loghunter.repository.ServerRepository;

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

@Service
@RequiredArgsConstructor
@Slf4j
public class ExportService {

    private final ErrorLogService errorLogService;
    private final ServerRepository serverRepository;
    private final SettingService settingService;

    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter FILE_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");

    /**
     * HTML 리포트 생성
     */
    public ExportResult exportHtml(ExportRequest request) {
        List<ErrorLogDto> errors = getErrors(request);
        String serverName = getServerName(request.serverId());
        String title = generateTitle(serverName, request);
        
        StringBuilder html = new StringBuilder();
        html.append("<!DOCTYPE html>\n");
        html.append("<html lang=\"ko\">\n");
        html.append("<head>\n");
        html.append("  <meta charset=\"UTF-8\">\n");
        html.append("  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n");
        html.append("  <title>").append(escapeHtml(title)).append("</title>\n");
        html.append("  <style>\n");
        html.append(getHtmlStyles());
        html.append("  </style>\n");
        html.append("</head>\n");
        html.append("<body>\n");
        
        // Header
        html.append("  <div class=\"header\">\n");
        html.append("    <h1>LogHunter 에러 리포트</h1>\n");
        html.append("    <p class=\"subtitle\">").append(escapeHtml(title)).append("</p>\n");
        html.append("    <p class=\"generated\">생성일시: ").append(LocalDateTime.now().format(DATE_FORMAT)).append("</p>\n");
        html.append("  </div>\n");
        
        // Summary
        html.append("  <div class=\"summary\">\n");
        html.append("    <h2>요약</h2>\n");
        html.append("    <ul>\n");
        html.append("      <li>총 에러 수: <strong>").append(errors.size()).append("</strong>건</li>\n");
        html.append("      <li>CRITICAL: <strong>").append(countBySeverity(errors, "CRITICAL")).append("</strong>건</li>\n");
        html.append("      <li>ERROR: <strong>").append(countBySeverity(errors, "ERROR")).append("</strong>건</li>\n");
        html.append("      <li>WARN: <strong>").append(countBySeverity(errors, "WARN")).append("</strong>건</li>\n");
        html.append("    </ul>\n");
        html.append("  </div>\n");
        
        // Error List
        html.append("  <div class=\"error-list\">\n");
        html.append("    <h2>에러 목록</h2>\n");
        
        if (errors.isEmpty()) {
            html.append("    <p class=\"no-data\">검출된 에러가 없습니다.</p>\n");
        } else {
            for (int i = 0; i < errors.size(); i++) {
                ErrorLogDto error = errors.get(i);
                html.append(renderErrorHtml(error, i + 1));
            }
        }
        
        html.append("  </div>\n");
        
        // Footer
        html.append("  <div class=\"footer\">\n");
        html.append("    <p>Generated by LogHunter</p>\n");
        html.append("  </div>\n");
        
        html.append("</body>\n");
        html.append("</html>");
        
        String filename = "loghunter_report_" + LocalDateTime.now().format(FILE_DATE_FORMAT) + ".html";
        return new ExportResult(filename, html.toString().getBytes(), "text/html");
    }

    /**
     * TXT 리포트 생성
     */
    public ExportResult exportTxt(ExportRequest request) {
        List<ErrorLogDto> errors = getErrors(request);
        String serverName = getServerName(request.serverId());
        String title = generateTitle(serverName, request);
        
        StringBuilder txt = new StringBuilder();
        txt.append("=".repeat(80)).append("\n");
        txt.append("LogHunter 에러 리포트\n");
        txt.append("=".repeat(80)).append("\n\n");
        
        txt.append("제목: ").append(title).append("\n");
        txt.append("생성일시: ").append(LocalDateTime.now().format(DATE_FORMAT)).append("\n\n");
        
        // Summary
        txt.append("-".repeat(40)).append("\n");
        txt.append("요약\n");
        txt.append("-".repeat(40)).append("\n");
        txt.append("총 에러 수: ").append(errors.size()).append("건\n");
        txt.append("  - CRITICAL: ").append(countBySeverity(errors, "CRITICAL")).append("건\n");
        txt.append("  - ERROR: ").append(countBySeverity(errors, "ERROR")).append("건\n");
        txt.append("  - WARN: ").append(countBySeverity(errors, "WARN")).append("건\n\n");
        
        // Error List
        txt.append("-".repeat(40)).append("\n");
        txt.append("에러 목록\n");
        txt.append("-".repeat(40)).append("\n\n");
        
        if (errors.isEmpty()) {
            txt.append("검출된 에러가 없습니다.\n");
        } else {
            for (int i = 0; i < errors.size(); i++) {
                ErrorLogDto error = errors.get(i);
                txt.append(renderErrorTxt(error, i + 1));
            }
        }
        
        txt.append("\n").append("=".repeat(80)).append("\n");
        txt.append("Generated by LogHunter\n");
        txt.append("=".repeat(80)).append("\n");
        
        String filename = "loghunter_report_" + LocalDateTime.now().format(FILE_DATE_FORMAT) + ".txt";
        return new ExportResult(filename, txt.toString().getBytes(), "text/plain");
    }

    private List<ErrorLogDto> getErrors(ExportRequest request) {
        return errorLogService.search(
                request.serverId(),
                request.patternId(),
                request.severity(),
                request.filePath(),
                request.startDate(),
                request.endDate(),
                request.keyword(),
                0,
                10000  // 최대 10000건
        ).getContent();
    }

    private String getServerName(Long serverId) {
        if (serverId == null) return "전체 서버";
        return serverRepository.findById(serverId)
                .map(Server::getName)
                .orElse("알 수 없음");
    }

    private String generateTitle(String serverName, ExportRequest request) {
        StringBuilder title = new StringBuilder();
        title.append(serverName);
        
        if (request.startDate() != null || request.endDate() != null) {
            title.append(" (");
            if (request.startDate() != null) {
                title.append(request.startDate().toLocalDate());
            }
            title.append(" ~ ");
            if (request.endDate() != null) {
                title.append(request.endDate().toLocalDate());
            }
            title.append(")");
        }
        
        return title.toString();
    }

    private long countBySeverity(List<ErrorLogDto> errors, String severity) {
        return errors.stream()
                .filter(e -> severity.equals(e.getSeverity()))
                .count();
    }

    private String renderErrorHtml(ErrorLogDto error, int index) {
        StringBuilder sb = new StringBuilder();
        sb.append("    <div class=\"error-item\">\n");
        sb.append("      <div class=\"error-header\">\n");
        sb.append("        <span class=\"index\">#").append(index).append("</span>\n");
        sb.append("        <span class=\"severity ").append(error.getSeverity().toLowerCase()).append("\">")
          .append(error.getSeverity()).append("</span>\n");
        sb.append("        <span class=\"time\">").append(formatDateTime(error.getOccurredAt())).append("</span>\n");
        sb.append("      </div>\n");
        sb.append("      <div class=\"error-meta\">\n");
        sb.append("        <span><strong>서버:</strong> ").append(escapeHtml(error.getServerName())).append("</span>\n");
        sb.append("        <span><strong>패턴:</strong> ").append(escapeHtml(error.getPatternName())).append("</span>\n");
        sb.append("        <span><strong>파일:</strong> ").append(escapeHtml(error.getFilePath())).append("</span>\n");
        sb.append("        <span><strong>라인:</strong> ").append(error.getLineNumber()).append("</span>\n");
        sb.append("      </div>\n");
        sb.append("      <div class=\"error-summary\">\n");
        sb.append("        <strong>요약:</strong> ").append(escapeHtml(error.getSummary())).append("\n");
        sb.append("      </div>\n");
        sb.append("      <div class=\"error-context\">\n");
        sb.append("        <strong>컨텍스트:</strong>\n");
        sb.append("        <pre>").append(escapeHtml(error.getContext())).append("</pre>\n");
        sb.append("      </div>\n");
        sb.append("    </div>\n");
        return sb.toString();
    }

    private String renderErrorTxt(ErrorLogDto error, int index) {
        StringBuilder sb = new StringBuilder();
        sb.append("[#").append(index).append("] ").append(error.getSeverity()).append("\n");
        sb.append("발생시간: ").append(formatDateTime(error.getOccurredAt())).append("\n");
        sb.append("서버: ").append(error.getServerName()).append("\n");
        sb.append("패턴: ").append(error.getPatternName()).append("\n");
        sb.append("파일: ").append(error.getFilePath()).append("\n");
        sb.append("라인: ").append(error.getLineNumber()).append("\n");
        sb.append("요약: ").append(error.getSummary()).append("\n");
        sb.append("컨텍스트:\n");
        sb.append(error.getContext()).append("\n");
        sb.append("-".repeat(60)).append("\n\n");
        return sb.toString();
    }

    private String formatDateTime(LocalDateTime dt) {
        return dt != null ? dt.format(DATE_FORMAT) : "-";
    }

    private String escapeHtml(String str) {
        if (str == null) return "";
        return str.replace("&", "&amp;")
                  .replace("<", "&lt;")
                  .replace(">", "&gt;")
                  .replace("\"", "&quot;")
                  .replace("'", "&#39;");
    }

    private String getHtmlStyles() {
        return """
            * { margin: 0; padding: 0; box-sizing: border-box; }
            body { font-family: 'Malgun Gothic', sans-serif; background: #f5f5f5; padding: 20px; }
            .header { background: #2c3e50; color: white; padding: 30px; border-radius: 8px; margin-bottom: 20px; }
            .header h1 { margin-bottom: 10px; }
            .header .subtitle { font-size: 18px; opacity: 0.9; }
            .header .generated { font-size: 14px; opacity: 0.7; margin-top: 10px; }
            .summary { background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
            .summary h2 { margin-bottom: 15px; color: #2c3e50; }
            .summary ul { list-style: none; }
            .summary li { padding: 8px 0; border-bottom: 1px solid #eee; }
            .summary li:last-child { border-bottom: none; }
            .error-list { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
            .error-list h2 { margin-bottom: 20px; color: #2c3e50; }
            .error-item { border: 1px solid #ddd; border-radius: 8px; margin-bottom: 15px; overflow: hidden; }
            .error-header { background: #f8f9fa; padding: 12px 15px; display: flex; align-items: center; gap: 15px; }
            .error-header .index { font-weight: bold; color: #666; }
            .error-header .severity { padding: 4px 10px; border-radius: 4px; font-size: 12px; font-weight: bold; color: white; }
            .error-header .severity.critical { background: #c0392b; }
            .error-header .severity.error { background: #e74c3c; }
            .error-header .severity.warn { background: #f39c12; }
            .error-header .time { margin-left: auto; color: #666; font-size: 14px; }
            .error-meta { padding: 12px 15px; background: #fafafa; display: flex; flex-wrap: wrap; gap: 20px; font-size: 14px; }
            .error-summary { padding: 12px 15px; border-bottom: 1px solid #eee; }
            .error-context { padding: 12px 15px; }
            .error-context pre { background: #2d2d2d; color: #f8f8f2; padding: 15px; border-radius: 4px; overflow-x: auto; font-size: 12px; line-height: 1.5; margin-top: 10px; white-space: pre-wrap; }
            .no-data { text-align: center; color: #666; padding: 40px; }
            .footer { text-align: center; padding: 20px; color: #666; font-size: 14px; }
            """;
    }

    // DTOs
    public record ExportRequest(
            Long serverId,
            Long patternId,
            String severity,
            String filePath,
            LocalDateTime startDate,
            LocalDateTime endDate,
            String keyword
    ) {}

    public record ExportResult(
            String filename,
            byte[] content,
            String contentType
    ) {}
}
