"""
Natural language test runner - orchestrates test execution, reporting, and notifications.
"""

import gc
import json
import os
import queue
import sys
import uuid
from datetime import datetime
from pathlib import Path
from typing import Optional

from dotenv import load_dotenv

# Ensure the backend directory is on the path when running from backend/main
_backend_dir = Path(__file__).resolve().parent.parent
if str(_backend_dir) not in sys.path:
    sys.path.insert(0, str(_backend_dir))

# Global queue for frontend notification (preserved from original)
test_status_queue = queue.Queue()

from core.logger import (
    setup_realtime_logging,
    get_logger,
    log_info,
    log_error,
    log_warning,
)
from runners.web_runner import WebRunner
from integrations.azure_blob import BlobStorageManager
from integrations.ado_integration import fetch_and_parse_test_cases
from reporting.reporter import ConsolidatedHTMLReporter
from reporting.report_separator import (
    prepare_client_report,
    prepare_internal_report,
)
from integrations.email_service import send_client_email, send_internal_email
# from integrations.emails_smtp_utils import send_client_email, send_internal_email

load_dotenv()
SHOW_HCLTECH_TESTCASE_ID = (
    str(os.getenv("HCLTech_TestCaseId", "true")).strip().lower() == "true"
)


class NaturalRunner:
    """
    Orchestrates natural language test execution: runs WebRunner,
    generates reports, uploads to blob storage, and sends email notifications.
    """

    def __init__(self):
        setup_realtime_logging()
        self.logger = get_logger(__name__)
        self._backend_dir = Path(__file__).resolve().parent.parent
        self._reports_dir = self._backend_dir / "reporting" / "reports" / "consolidated reports"

    async def run(self) -> None:
        """
        Main entry point: execute tests, generate reports, upload, and notify.
        """
        log_info("Starting Natural Language Test Runner")
        log_info("=" * 50)

        if not os.getenv("LOGIN_EMAIL") or not os.getenv("LOGIN_PASSWORD"):
            log_warning("LOGIN_EMAIL and LOGIN_PASSWORD not set.")
            log_warning("Tests will run without authentication.")
            log_warning("Set these environment variables for full functionality.")

        runner = None
        blob_storage = None
        try:
            log_info("Initializing test runner...")
            runner = WebRunner()

            log_info("Initializing blob storage...")
            blob_storage = BlobStorageManager()

            log_info("Starting test execution...")
            html_report = await runner.run()
            summary_data = runner.get_summary_data()
            test_run_id = str(uuid.uuid4())
            test_end_time = datetime.now()

            log_info("Uploading report to blob storage...")
            if html_report:
                report_url = blob_storage.upload_html_report(
                    html_report, test_run_id
                )
            else:
                log_warning(
                    "HTML report path is None; skipping upload to blob storage."
                )
                report_url = "N/A"

            test_status_queue.put(
                {
                    "type": "complete",
                    "htmlReport": html_report,
                    "excelReport": "reporting/reports/consolidated reports/latest_report.xlsx",
                    "reportUrl": report_url,
                    "message": "Test completed successfully",
                }
            )

            test_summary = {
                "columns": ["Total", "Passed", "Failed", "Skipped", "Pass %"],
                "values": [20, 14, 6, 0, "70%"],
            }
            execution_summary = {
                "columns": [
                    "Total Start Time",
                    "Total End Time",
                    "Total Duration",
                ],
                "values": ["10/7/2025 9:03", "10/7/2025 9:29", "0:26:00"],
            }

            log_info("Fetching test cases from ADO...")
            ado_plan_id = os.getenv("ADO_PLAN_ID")
            ado_suite_id = os.getenv("ADO_SUITE_ID")
            ado_testcase_id = os.getenv("ADO_TESTCASE_ID")

            try:
                test_cases = fetch_and_parse_test_cases(
                    ado_plan_id, ado_suite_id, ado_testcase_id
                )
                log_info(
                    f"Successfully fetched {len(test_cases)} test cases from ADO"
                )
                for tc in test_cases:
                    tags = tc.get("tags", [])
                    log_info(f"  Test Case {tc.get('id')}: tags={tags}")
            except Exception as e:
                log_warning(f"Failed to fetch test cases from ADO: {e}")
                test_cases = []

            latest_json = self._reports_dir / "latest_report.json"
            test_case_id_mapping = {}
            if latest_json.exists():
                with open(latest_json, "r", encoding="utf-8") as f:
                    data = json.load(f)
                rows = data.get("rows", [])
                if rows:
                    for r in rows:
                        tc_id = str(r.get("Test Case ID", ""))
                        ado_id = str(r.get("HCLTech ADO ID", ""))
                        if tc_id and ado_id:
                            test_case_id_mapping[tc_id] = ado_id

            ado_id_to_tags = {}
            for tc in test_cases:
                work_item_id = str(tc.get("id", "")).strip()
                tags = tc.get("tags", [])
                ado_id_to_tags[work_item_id] = tags

            detailed_columns = ["Test Case ID"]
            if SHOW_HCLTECH_TESTCASE_ID:
                detailed_columns.append("HCLTech ADO ID")
            detailed_columns.extend(
                [
                    "Priority",
                    "Test Case Title",
                    "Duration",
                    "Status",
                    "Failure Message",
                ]
            )
            detailed_report = {"columns": detailed_columns, "rows": []}

            mapped_rows = []
            if latest_json.exists():
                with open(latest_json, "r", encoding="utf-8") as f:
                    data = json.load(f)
                rows = data.get("rows", [])
                if rows:
                    enriched_test_cases = []
                    for r in rows:
                        tc_id = str(r.get("Test Case ID", "")).strip()
                        ado_id = str(r.get("HCLTech ADO ID", "")).strip()
                        tags = ado_id_to_tags.get(ado_id, [])
                        enriched_test_cases.append(
                            {
                                "id": tc_id,
                                "title": r.get("Test Case Title", ""),
                                "tags": tags,
                            }
                        )
                    test_cases = enriched_test_cases

                steps = data.get("steps", [])
                total_steps = len(steps)
                passed_steps = sum(
                    1
                    for entry in steps
                    if str(entry.get("result", "")).lower()
                    in ["passed", "ok", "success", ""]
                )
                run_start_time = (
                    runner.test_start_time.strftime("%Y-%m-%d %H:%M:%S")
                    if hasattr(runner, "test_start_time")
                    and runner.test_start_time
                    else (
                        steps[0].get("timestamp", "")
                        if steps and "timestamp" in steps[0]
                        else data.get(
                            "test_start_time",
                            datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                        )
                    )
                )
                run_end_time = test_end_time.strftime("%Y-%m-%d %H:%M:%S")
                steps_summary = summary_data if isinstance(summary_data, dict) else {}
                summary_data = {
                    "Run Start Time": run_start_time,
                    "Run End Time": run_end_time,
                    "Total Steps": steps_summary.get(
                        "total_steps", total_steps
                    ),
                    "Total Steps Passed": steps_summary.get(
                        "passed_steps", passed_steps
                    ),
                    "Total Steps Failed": steps_summary.get(
                        "failed_steps", total_steps - passed_steps
                    ),
                }

                if rows:
                    mapped_rows = [
                        {
                            "Test Case ID": f"<a href='https://microsoft.visualstudio.com/OS/_workitems/edit/{r.get('Test Case ID', r.get('Microsoft ADO ID', r.get('id', 0)))}' target='_blank'>{r.get('Test Case ID', r.get('Microsoft ADO ID', r.get('id', 0)))}</a>",
                            "HCLTech ADO ID": r.get("HCLTech ADO ID", 0),
                            "Priority": r.get(
                                "Priority", r.get("priority", "")
                            ),
                            "Test Case Title": r.get(
                                "Test Case Title", r.get("title", "")
                            ),
                            "Duration": r.get("Duration", ""),
                            "Status": r.get(
                                "Status", r.get("status", "")
                            ).title(),
                            "Failure Message": r.get(
                                "Failure Message",
                                r.get("failure_message", ""),
                            ),
                        }
                        for r in rows
                    ]
                    if not SHOW_HCLTECH_TESTCASE_ID:
                        for row in mapped_rows:
                            row.pop("HCLTech ADO ID", None)
                    detailed_report["rows"] = mapped_rows

                    statuses_lower = [
                        str(r.get("Status", "")).lower() for r in mapped_rows
                    ]
                    passed_count = sum(
                        1 for s in statuses_lower if s == "passed"
                    )
                    failed_count = sum(
                        1 for s in statuses_lower if s == "failed"
                    )
                    skipped_count = sum(
                        1 for s in statuses_lower if s == "skipped"
                    )
                    total_count = (
                        passed_count + failed_count + skipped_count
                    )
                    pass_percent = (
                        f"{int((passed_count / total_count) * 100)}%"
                        if total_count
                        else "0%"
                    )
                    test_summary["values"] = [
                        total_count,
                        passed_count,
                        failed_count,
                        skipped_count,
                        pass_percent,
                    ]

            login_url = os.environ.get("LOGIN_URL", "N/A")

            client_should_send, client_report_data = prepare_client_report(
                mapped_rows,
                test_cases,
                detailed_report,
                summary_data,
                test_summary,
            )
            internal_report_data = prepare_internal_report(
                mapped_rows,
                test_cases,
                detailed_report,
                summary_data,
                test_summary,
            )

            client_html_path = None
            internal_html_path = None

            self._reports_dir.mkdir(parents=True, exist_ok=True)

            client_test_ids = {
                str(tc.get("id"))
                for tc in client_report_data["test_cases"]
                if tc.get("id")
            }
            internal_test_ids = {
                str(tc.get("id"))
                for tc in internal_report_data["test_cases"]
                if tc.get("id")
            }

            all_testcase_results = getattr(
                runner, "all_testcase_results", []
            )

            for result in all_testcase_results:
                tc_id = str(result.get("id", ""))
                if tc_id in test_case_id_mapping:
                    result["ado_id"] = test_case_id_mapping[tc_id]

            if client_test_ids and all_testcase_results:
                client_filtered = [
                    r
                    for r in all_testcase_results
                    if str(r.get("id", "")) in client_test_ids
                ]
                log_info(
                    f"CLIENT filtered results count: {len(client_filtered)}"
                )
                if client_filtered:
                    log_info(
                        f"Generating CLIENT HTML report with "
                        f"{len(client_filtered)} test cases..."
                    )
                    client_html_path = (
                        self._reports_dir
                        / f"report_client_{datetime.now().strftime('%Y%m%d_%H%M%S')}.html"
                    )
                    try:
                        ConsolidatedHTMLReporter(
                            client_filtered,
                            html_report=str(client_html_path),
                            test_start_time=runner.test_start_time
                            if hasattr(runner, "test_start_time")
                            else datetime.now(),
                            test_end_time=test_end_time,
                            show_ado_id=False,
                        ).generate_html_report()
                    except Exception as e:
                        log_error(f"Failed to generate CLIENT HTML: {e}")
                        client_html_path = None

            if internal_test_ids and all_testcase_results:
                internal_filtered = [
                    r
                    for r in all_testcase_results
                    if str(r.get("id", "")) in internal_test_ids
                ]
                if internal_filtered:
                    internal_html_path = (
                        self._reports_dir
                        / f"report_internal_{datetime.now().strftime('%Y%m%d_%H%M%S')}.html"
                    )
                    try:
                        ConsolidatedHTMLReporter(
                            internal_filtered,
                            html_report=str(internal_html_path),
                            test_start_time=runner.test_start_time
                            if hasattr(runner, "test_start_time")
                            else datetime.now(),
                            test_end_time=test_end_time,
                            show_ado_id=True,
                        ).generate_html_report()
                    except Exception as e:
                        log_error(
                            f"Failed to generate INTERNAL HTML: {e}"
                        )
                        internal_html_path = None
                else:
                    log_warning(
                        f"No INTERNAL results matched. "
                        f"Expected IDs: {internal_test_ids}"
                    )

            client_report_url = report_url
            internal_report_url = report_url

            log_info(
                "UPLOADING CLIENT AND INTERNAL HTML REPORTS TO BLOB STORAGE"
            )
            try:
                if client_html_path and client_html_path.exists():
                    try:
                        client_report_url = blob_storage.upload_html_report(
                            str(client_html_path),
                            f"{test_run_id}_client",
                        )
                    except Exception as e:
                        log_warning(f"Client report upload failed: {e}")

                if internal_html_path and internal_html_path.exists():
                    try:
                        internal_report_url = blob_storage.upload_html_report(
                            str(internal_html_path),
                            f"{test_run_id}_internal",
                        )
                    except Exception as e:
                        log_warning(f"Internal report upload failed: {e}")
            except Exception as e:
                log_error(f"Error uploading reports: {str(e)[:200]}")

            if client_should_send:
                log_info(
                    "Sending CLIENT email with Microsoft test cases only..."
                )
                client_email_sent = send_client_email(
                    report_url,
                    login_url,
                    client_report_data["summary_data"],
                    client_report_data["test_cases"],
                    client_report_data["test_summary"],
                    execution_summary,
                    client_report_data["detailed_report"],
                    should_send=True,
                    client_report_url=client_report_url,
                )
                if client_email_sent:
                    log_info("CLIENT email sent successfully!")
                else:
                    log_warning("CLIENT email failed to send.")
            else:
                log_warning(
                    "CLIENT email NOT sent: Pass percentage below threshold"
                )

            log_info("Sending INTERNAL email with all test cases...")
            internal_email_sent = send_internal_email(
                report_url,
                login_url,
                internal_report_data["summary_data"],
                internal_report_data["test_cases"],
                internal_report_data["test_summary"],
                execution_summary,
                internal_report_data["detailed_report"],
                internal_report_url=internal_report_url,
            )
            if internal_email_sent:
                log_info("INTERNAL email sent successfully!")
            else:
                log_warning("INTERNAL email failed to send.")

            log_info("Test execution completed successfully!")

        except Exception as e:
            log_error(f"Test execution failed: {e}")
            import traceback

            log_error(f"Full error traceback: {traceback.format_exc()}")
            if runner:
                try:
                    await runner.cleanup()
                except Exception as cleanup_error:
                    log_error(f"Error during cleanup: {cleanup_error}")
            sys.exit(1)
        finally:
            gc.collect()


def main() -> None:
    """Entry point for running natural language tests."""
    import asyncio

    asyncio.run(NaturalRunner().run())


if __name__ == "__main__":
    main()
