package com.openosrs.client.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Queue;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * Test reporting and statistics components.
 */

// ================================
// TEST REPORTING
// ================================

/**
 * Generates reports and statistics for test results.
 */
class TestReporter {
    private static final Logger logger = LoggerFactory.getLogger(TestReporter.class);
    private static final DateTimeFormatter TIMESTAMP_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    
    public void recordResult(TestResult result) {
        logger.info("Test result recorded: {} - {} ({}ms)", 
            result.getTestName(), result.getStatus(), result.getDurationMs());
    }
    
    public TestStatistics generateStatistics(Queue<TestResult> results) {
        List<TestResult> resultList = new ArrayList<>(results);
        
        long totalTests = resultList.size();
        long passedTests = resultList.stream()
            .filter(r -> r.getStatus() == TestStatus.PASSED)
            .count();
        long failedTests = resultList.stream()
            .filter(r -> r.getStatus() == TestStatus.FAILED)
            .count();
        long timeoutTests = resultList.stream()
            .filter(r -> r.getStatus() == TestStatus.TIMEOUT)
            .count();
        
        double averageDuration = resultList.stream()
            .filter(r -> r.getDurationMs() > 0)
            .mapToLong(TestResult::getDurationMs)
            .average()
            .orElse(0.0);
        
        long totalDuration = resultList.stream()
            .mapToLong(TestResult::getDurationMs)
            .sum();
        
        // Group by test name for success rates
        Map<String, List<TestResult>> groupedResults = resultList.stream()
            .collect(Collectors.groupingBy(TestResult::getTestName));
        
        Map<String, Double> successRates = new HashMap<>();
        for (Map.Entry<String, List<TestResult>> entry : groupedResults.entrySet()) {
            String testName = entry.getKey();
            List<TestResult> testResults = entry.getValue();
            
            long successful = testResults.stream()
                .filter(r -> r.getStatus() == TestStatus.PASSED)
                .count();
            
            double successRate = testResults.isEmpty() ? 0.0 : (double) successful / testResults.size() * 100.0;
            successRates.put(testName, successRate);
        }
        
        return new TestStatistics(
            totalTests, passedTests, failedTests, timeoutTests,
            averageDuration, totalDuration, successRates
        );
    }
    
    public void exportResults(Queue<TestResult> results, String format, String outputPath) {
        try {
            switch (format.toLowerCase()) {
                case "json":
                    exportToJson(results, outputPath);
                    break;
                case "csv":
                    exportToCsv(results, outputPath);
                    break;
                case "html":
                    exportToHtml(results, outputPath);
                    break;
                default:
                    logger.warn("Unsupported export format: {}", format);
            }
        } catch (IOException e) {
            logger.error("Failed to export test results to {}", outputPath, e);
        }
    }
    
    private void exportToJson(Queue<TestResult> results, String outputPath) throws IOException {
        StringBuilder json = new StringBuilder();
        json.append("{\n");
        json.append("  \"test_results\": [\n");
        
        List<TestResult> resultList = new ArrayList<>(results);
        for (int i = 0; i < resultList.size(); i++) {
            TestResult result = resultList.get(i);
            json.append("    {\n");
            json.append(String.format("      \"test_id\": \"%s\",\n", result.getTestId()));
            json.append(String.format("      \"test_name\": \"%s\",\n", result.getTestName()));
            json.append(String.format("      \"status\": \"%s\",\n", result.getStatus()));
            json.append(String.format("      \"message\": \"%s\",\n", result.getMessage()));
            json.append(String.format("      \"duration_ms\": %d,\n", result.getDurationMs()));
            json.append(String.format("      \"timestamp\": \"%s\"\n", result.getTimestamp().format(TIMESTAMP_FORMAT)));
            json.append("    }");
            if (i < resultList.size() - 1) {
                json.append(",");
            }
            json.append("\n");
        }
        
        json.append("  ]\n");
        json.append("}");
        
        Files.write(Paths.get(outputPath), json.toString().getBytes());
        logger.info("Test results exported to JSON: {}", outputPath);
    }
    
    private void exportToCsv(Queue<TestResult> results, String outputPath) throws IOException {
        StringBuilder csv = new StringBuilder();
        csv.append("test_id,test_name,status,message,duration_ms,timestamp\n");
        
        for (TestResult result : results) {
            csv.append(String.format("%s,%s,%s,\"%s\",%d,%s\n",
                result.getTestId(),
                result.getTestName(),
                result.getStatus(),
                result.getMessage().replace("\"", "\\\""),
                result.getDurationMs(),
                result.getTimestamp().format(TIMESTAMP_FORMAT)
            ));
        }
        
        Files.write(Paths.get(outputPath), csv.toString().getBytes());
        logger.info("Test results exported to CSV: {}", outputPath);
    }
    
    private void exportToHtml(Queue<TestResult> results, String outputPath) throws IOException {
        StringBuilder html = new StringBuilder();
        html.append("<!DOCTYPE html>\n");
        html.append("<html>\n<head>\n<title>Test Results</title>\n");
        html.append("<style>\n");
        html.append("table { border-collapse: collapse; width: 100%; }\n");
        html.append("th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }\n");
        html.append("th { background-color: #f2f2f2; }\n");
        html.append(".passed { color: green; }\n");
        html.append(".failed { color: red; }\n");
        html.append(".timeout { color: orange; }\n");
        html.append("</style>\n</head>\n<body>\n");
        
        html.append("<h1>Test Results Report</h1>\n");
        html.append(String.format("<p>Generated on: %s</p>\n", LocalDateTime.now().format(TIMESTAMP_FORMAT)));
        
        TestStatistics stats = generateStatistics(results);
        html.append("<h2>Summary</h2>\n");
        html.append("<ul>\n");
        html.append(String.format("<li>Total Tests: %d</li>\n", stats.getTotalTests()));
        html.append(String.format("<li>Passed: %d</li>\n", stats.getPassedTests()));
        html.append(String.format("<li>Failed: %d</li>\n", stats.getFailedTests()));
        html.append(String.format("<li>Timeouts: %d</li>\n", stats.getTimeoutTests()));
        html.append(String.format("<li>Average Duration: %.2f ms</li>\n", stats.getAverageDuration()));
        html.append("</ul>\n");
        
        html.append("<h2>Test Results</h2>\n");
        html.append("<table>\n");
        html.append("<tr><th>Test Name</th><th>Status</th><th>Message</th><th>Duration (ms)</th><th>Timestamp</th></tr>\n");
        
        for (TestResult result : results) {
            String statusClass = result.getStatus().toString().toLowerCase();
            html.append(String.format("<tr><td>%s</td><td class=\"%s\">%s</td><td>%s</td><td>%d</td><td>%s</td></tr>\n",
                result.getTestName(),
                statusClass,
                result.getStatus(),
                result.getMessage(),
                result.getDurationMs(),
                result.getTimestamp().format(TIMESTAMP_FORMAT)
            ));
        }
        
        html.append("</table>\n");
        html.append("</body>\n</html>");
        
        Files.write(Paths.get(outputPath), html.toString().getBytes());
        logger.info("Test results exported to HTML: {}", outputPath);
    }
}

// ================================
// TEST STATISTICS
// ================================

/**
 * Comprehensive test statistics.
 */
class TestStatistics {
    private final long totalTests;
    private final long passedTests;
    private final long failedTests;
    private final long timeoutTests;
    private final double averageDuration;
    private final long totalDuration;
    private final Map<String, Double> successRates;
    private final LocalDateTime generatedAt;
    
    public TestStatistics(long totalTests, long passedTests, long failedTests, long timeoutTests,
                         double averageDuration, long totalDuration, Map<String, Double> successRates) {
        this.totalTests = totalTests;
        this.passedTests = passedTests;
        this.failedTests = failedTests;
        this.timeoutTests = timeoutTests;
        this.averageDuration = averageDuration;
        this.totalDuration = totalDuration;
        this.successRates = new HashMap<>(successRates);
        this.generatedAt = LocalDateTime.now();
    }
    
    public long getTotalTests() { return totalTests; }
    public long getPassedTests() { return passedTests; }
    public long getFailedTests() { return failedTests; }
    public long getTimeoutTests() { return timeoutTests; }
    public double getAverageDuration() { return averageDuration; }
    public long getTotalDuration() { return totalDuration; }
    public Map<String, Double> getSuccessRates() { return new HashMap<>(successRates); }
    public LocalDateTime getGeneratedAt() { return generatedAt; }
    
    public double getSuccessRate() {
        return totalTests == 0 ? 0.0 : (double) passedTests / totalTests * 100.0;
    }
    
    public double getFailureRate() {
        return totalTests == 0 ? 0.0 : (double) failedTests / totalTests * 100.0;
    }
    
    public double getTimeoutRate() {
        return totalTests == 0 ? 0.0 : (double) timeoutTests / totalTests * 100.0;
    }
    
    @Override
    public String toString() {
        return String.format(
            "TestStatistics{total=%d, passed=%d, failed=%d, timeouts=%d, successRate=%.2f%%, avgDuration=%.2fms}",
            totalTests, passedTests, failedTests, timeoutTests, getSuccessRate(), averageDuration
        );
    }
}