use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestReport {
    pub name: String,
    pub timestamp: String,
    pub elapsed_ms: u64,
    pub suites: Vec<TestSuite>,
    pub summary: TestSummary,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestSummary {
    pub total_cases: u64,
    pub passed: u64,
    pub failed: u64,
    pub pass_rate: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestSuite {
    pub name: String,
    pub description: String,
    pub cases: Vec<TestCase>,
    pub total: u64,
    pub passed: u64,
    pub failed: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestCase {
    pub id: String,
    pub name: String,
    pub category: String,
    pub steps: Vec<TestStep>,
    pub expected_result: String,
    pub actual_result: String,
    pub status: TestStatus,
    pub error_message: Option<String>,
    pub severity: Severity,
    pub business_logic_verified: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestStep {
    pub step_number: u32,
    pub action: String,
    pub expected: String,
    pub actual: String,
    pub duration_ms: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum TestStatus {
    Pass,
    Fail,
    Skipped,
    Blocked,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Severity {
    Critical,
    High,
    Medium,
    Low,
}

impl TestReport {
    pub fn new(name: String) -> Self {
        Self {
            name,
            timestamp: chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC").to_string(),
            elapsed_ms: 0,
            suites: Vec::new(),
            summary: TestSummary {
                total_cases: 0,
                passed: 0,
                failed: 0,
                pass_rate: 0.0,
            },
        }
    }

    pub fn add_suite(&mut self, suite: TestSuite) {
        self.summary.total_cases += suite.total;
        self.summary.passed += suite.passed;
        self.summary.failed += suite.failed;
        self.suites.push(suite);
    }

    pub fn finalize(&mut self) {
        if self.summary.total_cases > 0 {
            self.summary.pass_rate = (self.summary.passed as f64 / self.summary.total_cases as f64) * 100.0;
        }
    }

    pub fn print_summary(&self) {
        println!("\n");
        println!("╔══════════════════════════════════════════════════════════════════════╗");
        println!("║          ERP PLATFORM INTEGRATION TEST REPORT                       ║");
        println!("╠══════════════════════════════════════════════════════════════════════╣");
        println!("║  Timestamp: {}                                      ║", self.timestamp);
        println!("║  Total Duration: {} ms                                            ║", self.elapsed_ms);
        println!("╠══════════════════════════════════════════════════════════════════════╣");
        println!("║  OVERALL SUMMARY                                                    ║");
        println!("║  ├─ Total Test Cases: {}                                            ║", self.summary.total_cases);
        println!("║  ├─ Passed:  ✓ {}                                                   ║", self.summary.passed);
        println!("║  ├─ Failed:  ✗ {}                                                   ║", self.summary.failed);
        println!("║  └─ Pass Rate: {:.2}%                                              ║", self.summary.pass_rate);
        println!("╠══════════════════════════════════════════════════════════════════════╣");

        for suite in &self.suites {
            let status_icon = if suite.failed == 0 { "✓" } else { "✗" };
            println!("║  {} {} ({}/{} passed, {} failed)", status_icon, suite.name, suite.passed, suite.total, suite.failed);
        }
        println!("╚══════════════════════════════════════════════════════════════════════╝");
    }

    pub fn generate_markdown_report(&self) -> String {
        let mut md = String::new();
        md.push_str("# ERP Platform Full Integration Test Report\n\n");
        md.push_str(&format!("**Generated:** {}  \n", self.timestamp));
        md.push_str(&format!("**Total Duration:** {} ms  \n\n", self.elapsed_ms));

        md.push_str("## Executive Summary\n\n");
        md.push_str(&format!("| Metric | Value |\n"));
        md.push_str(&format!("|--------|-------|\n"));
        md.push_str(&format!("| Total Test Cases | {} |\n", self.summary.total_cases));
        md.push_str(&format!("| Passed | {} |\n", self.summary.passed));
        md.push_str(&format!("| Failed | {} |\n", self.summary.failed));
        md.push_str(&format!("| Pass Rate | {:.2}% |\n\n", self.summary.pass_rate));

        md.push_str("## Test Suites\n\n");
        for suite in &self.suites {
            md.push_str(&format!("### {}\n\n", suite.name));
            md.push_str(&format!("*{}*\n\n", suite.description));
            md.push_str(&format!("**Results:** {} passed, {} failed out of {} total\n\n", suite.passed, suite.failed, suite.total));

            md.push_str("| ID | Test Case | Severity | Status | Business Logic |\n");
            md.push_str("|----|-----------|----------|--------|----------------|\n");
            for case in &suite.cases {
                let status_icon = match case.status {
                    TestStatus::Pass => "✓ PASS",
                    TestStatus::Fail => "✗ FAIL",
                    TestStatus::Skipped => "⊘ SKIP",
                    TestStatus::Blocked => "⊗ BLOCK",
                };
                let biz_logic = if case.business_logic_verified { "✓" } else { "✗" };
                md.push_str(&format!("| {} | {} | {:?} | {} | {} |\n",
                    case.id, case.name, case.severity, status_icon, biz_logic));
            }
            md.push_str("\n");

            for case in &suite.cases {
                if case.status == TestStatus::Fail {
                    md.push_str(&format!("#### {}: {}\n\n", case.id, case.name));
                    md.push_str(&format!("**Severity:** {:?}  \n", case.severity));
                    md.push_str(&format!("**Expected:** {}  \n", case.expected_result));
                    md.push_str(&format!("**Actual:** {}  \n\n", case.actual_result));
                    if let Some(ref err) = case.error_message {
                        md.push_str(&format!("**Error:** `{}`  \n\n", err));
                    }
                    md.push_str("**Test Steps:**\n\n");
                    for step in &case.steps {
                        md.push_str(&format!("{}. **{}**  \n   - Expected: {}  \n   - Actual: {}  \n   - Duration: {}ms  \n\n",
                            step.step_number, step.action, step.expected, step.actual, step.duration_ms));
                    }
                    md.push_str("---\n\n");
                }
            }
        }

        md
    }
}

impl TestSuite {
    pub fn new(name: &str, description: &str) -> Self {
        Self {
            name: name.to_string(),
            description: description.to_string(),
            cases: Vec::new(),
            total: 0,
            passed: 0,
            failed: 0,
        }
    }

    pub fn add_case(&mut self, case: TestCase) {
        self.total += 1;
        match case.status {
            TestStatus::Pass => self.passed += 1,
            TestStatus::Fail => self.failed += 1,
            _ => {}
        }
        self.cases.push(case);
    }
}

impl TestCase {
    pub fn new(id: &str, name: &str, category: &str) -> Self {
        Self {
            id: id.to_string(),
            name: name.to_string(),
            category: category.to_string(),
            steps: Vec::new(),
            expected_result: String::new(),
            actual_result: String::new(),
            status: TestStatus::Fail,
            error_message: None,
            severity: Severity::Medium,
            business_logic_verified: false,
        }
    }

    pub fn with_steps(mut self, steps: Vec<TestStep>) -> Self {
        self.steps = steps;
        self
    }

    pub fn with_expected(mut self, expected: &str) -> Self {
        self.expected_result = expected.to_string();
        self
    }

    pub fn with_actual(mut self, actual: &str) -> Self {
        self.actual_result = actual.to_string();
        self
    }

    pub fn with_status(mut self, status: TestStatus) -> Self {
        self.status = status;
        self
    }

    pub fn with_error(mut self, error: Option<String>) -> Self {
        self.error_message = error;
        self
    }

    pub fn with_severity(mut self, severity: Severity) -> Self {
        self.severity = severity;
        self
    }

    pub fn verify_business_logic(mut self, verified: bool) -> Self {
        self.business_logic_verified = verified;
        self
    }

    pub fn add_step(&mut self, step: TestStep) {
        self.steps.push(step);
    }
}

impl TestStep {
    pub fn new(step_number: u32, action: &str, expected: &str) -> Self {
        Self {
            step_number,
            action: action.to_string(),
            expected: expected.to_string(),
            actual: String::new(),
            duration_ms: 0,
        }
    }

    pub fn with_actual(mut self, actual: &str, duration_ms: u64) -> Self {
        self.actual = actual.to_string();
        self.duration_ms = duration_ms;
        self
    }
}