"""
FunnelMapperScenario — Captures screenshots at every step of the user journey
and generates a funnel map report.

This scenario chains all other scenarios and instruments each step with:
  - Numbered screenshot per step
  - Time taken per step
  - Selectors found / not found
  - Final JSON report saved to testing/reports/{product}_funnel_map.json

config keys:
    All keys from: SignupScenario, LoginScenario, PlanSelectScenario,
                   CheckoutScenario, DashboardScenario
    funnel_steps (list[str])    — ordered list of steps to run, e.g.:
                                  ["signup", "plan_select", "checkout", "dashboard"]
                                  Default: all steps in order.
    skip_signup (bool)          — if True, skip signup and go straight to login
    product (str)               — used in report filename
"""

import json
import time
from datetime import datetime
from pathlib import Path
from typing import Any

from .base import BaseScenario, ScenarioResult, StepResult, SCREENSHOTS_DIR
from .signup import SignupScenario
from .login import LoginScenario
from .plan_select import PlanSelectScenario
from .checkout import CheckoutScenario
from .dashboard import DashboardScenario

REPORTS_DIR = Path("/mnt/e/genesis-system/testing/reports")
REPORTS_DIR.mkdir(parents=True, exist_ok=True)

ALL_STEP_NAMES = ["signup", "login", "plan_select", "checkout", "dashboard"]

SCENARIO_MAP = {
    "signup": SignupScenario,
    "login": LoginScenario,
    "plan_select": PlanSelectScenario,
    "checkout": CheckoutScenario,
    "dashboard": DashboardScenario,
}


class FunnelMapperScenario(BaseScenario):
    name = "funnel_mapper"

    def __init__(self) -> None:
        super().__init__()
        self._funnel_report: list[dict] = []
        self._step_counter: int = 0

    async def run(self, page: Any, config: dict) -> None:
        product = config.get("product", "unknown")
        funnel_steps = config.get("funnel_steps", ALL_STEP_NAMES)

        self._log(f"Funnel map for product='{product}', steps={funnel_steps}")

        for step_name in funnel_steps:
            scenario_cls = SCENARIO_MAP.get(step_name)
            if not scenario_cls:
                step = self._new_step(f"unknown_step_{step_name}")
                self._finish_step(step, "error", f"No scenario registered for '{step_name}'")
                self._record_funnel_entry(step_name, step, page)
                continue

            self._step_counter += 1
            scenario = scenario_cls()
            # Share same page, same config, same timeout
            scenario._page = page
            scenario._config = config
            scenario._timeout = self._timeout
            # We need a result object
            from .base import ScenarioResult
            scenario.result = ScenarioResult(step_name, product)

            step_start = time.time()
            sub_result = await scenario.execute(page, config)
            step_duration = round((time.time() - step_start) * 1000, 1)

            # Capture numbered funnel screenshot
            screenshot_label = f"{self._step_counter:02d}_{step_name}"
            screenshot_path = await self._screenshot(screenshot_label)

            # Build funnel entry
            funnel_entry = {
                "step_number": self._step_counter,
                "step_name": step_name,
                "status": sub_result.overall_status,
                "duration_ms": step_duration,
                "screenshot_path": screenshot_path,
                "sub_steps": [s.to_dict() for s in sub_result.steps],
                "selectors_found": [
                    s.name for s in sub_result.steps if s.status == "pass"
                ],
                "selectors_failed": [
                    s.name for s in sub_result.steps if s.status in ("fail", "error")
                ],
            }
            self._funnel_report.append(funnel_entry)

            # Add a meta step to main result
            meta = StepResult(f"funnel_step_{self._step_counter:02d}_{step_name}")
            meta.screenshot_path = screenshot_path
            meta.complete(
                sub_result.overall_status,
                f"{step_name}: {sub_result.overall_status} ({step_duration}ms)",
            )
            self.result.add_step(meta)

            # Stop funnel on first error (can't proceed without auth, etc.)
            if sub_result.overall_status == "fail" and step_name in ("signup", "login"):
                self._log(f"Critical step '{step_name}' failed — stopping funnel")
                break

        # -- Generate report
        await self._generate_report(product)

    async def _generate_report(self, product: str) -> None:
        step = self._new_step("generate_funnel_report")
        try:
            ts = datetime.utcnow().strftime("%Y%m%dT%H%M%S")
            report = {
                "product": product,
                "generated_at": ts,
                "total_steps": self._step_counter,
                "passed_steps": sum(1 for e in self._funnel_report if e["status"] == "pass"),
                "failed_steps": sum(1 for e in self._funnel_report if e["status"] != "pass"),
                "funnel": self._funnel_report,
            }
            report_path = REPORTS_DIR / f"{product}_funnel_map.json"
            report_path.write_text(json.dumps(report, indent=2))
            self._finish_step(step, "pass", f"Funnel report saved: {report_path}")
        except Exception as exc:
            self._finish_step(step, "error", f"Failed to write report: {exc}")

    def _record_funnel_entry(self, step_name: str, step: StepResult, page: Any) -> None:
        self._funnel_report.append(
            {
                "step_number": self._step_counter,
                "step_name": step_name,
                "status": step.status,
                "duration_ms": step.duration_ms,
                "screenshot_path": step.screenshot_path or "",
                "sub_steps": [],
                "selectors_found": [],
                "selectors_failed": [step.name],
            }
        )
