"""Flow generator — auto-create YAML flows from the navigation graph.

Uses the crawl results (pages, forms, inputs, buttons) to generate
starter flow YAML files.  When an LLM is available (Phase 6), this
can be enhanced with AI-assisted descriptions and smarter step ordering.
For now, it uses deterministic heuristics.
"""

from __future__ import annotations

import logging
from pathlib import Path
from typing import Any

import yaml

from antiqa.crawler.graph import NavigationGraph, PageNode

log = logging.getLogger("antiqa.flows")


class FlowGenerator:
    """Generate YAML flow files from a NavigationGraph."""

    def __init__(
        self,
        graph: NavigationGraph,
        app_url: str,
        flows_dir: str | Path = "flows/",
    ) -> None:
        self.graph = graph
        self.app_url = app_url.rstrip("/")
        self.flows_dir = Path(flows_dir)
        self.flows_dir.mkdir(parents=True, exist_ok=True)

    def generate_all(self, overwrite: bool = False) -> list[Path]:
        """Generate flows for all discoverable patterns and return saved paths."""
        generated: list[Path] = []

        for node in self.graph.nodes.values():
            if node.forms:
                for i, form in enumerate(node.forms):
                    path = self._generate_form_flow(node, form, index=i, overwrite=overwrite)
                    if path:
                        generated.append(path)

        return generated

    def _generate_form_flow(
        self,
        node: PageNode,
        form: dict[str, Any],
        index: int = 0,
        overwrite: bool = False,
    ) -> Path | None:
        """Generate a flow for a form on a given page."""
        page_name = node.url_pattern.strip("/").replace("/", "_").replace("{id}", "id") or "home"
        flow_name = f"auto_{page_name}" if index == 0 else f"auto_{page_name}_form{index}"

        path = self.flows_dir / f"{flow_name}.yaml"
        if path.exists() and not overwrite:
            log.debug("Skipping %s (already exists)", path)
            return None

        fields = form.get("fields", [])
        form_selector = form.get("selector", "form")
        method = form.get("method", "POST")

        is_login = self._looks_like_login(node, fields)

        steps: list[dict[str, Any]] = []
        params: dict[str, str] = {}

        steps.append({
            "action": "navigate",
            "url": f"{{{{app_url}}}}{node.url_pattern}",
            "description": f"Open {node.title or node.url_pattern}",
        })

        steps.append({
            "action": "wait_for",
            "selector": form_selector,
            "description": "Wait for form to load",
        })

        for field_selector in fields:
            param_name = self._selector_to_param(field_selector)
            field_type = self._guess_field_type(field_selector, is_login)

            if field_type == "password":
                params[param_name] = "{{test_password}}"
            elif field_type == "email":
                params[param_name] = "{{test_email}}"
            else:
                params[param_name] = f"test_{param_name}"

            steps.append({
                "action": "fill",
                "selector": field_selector,
                "value": f"{{{{{param_name}}}}}",
                "description": f"Fill {param_name}",
            })

        submit_selector = self._find_submit_selector(node, form_selector)
        steps.append({
            "action": "click",
            "selector": submit_selector,
            "description": "Submit the form",
        })

        steps.append({
            "action": "screenshot",
            "name": f"{flow_name}_result",
            "description": "Capture result after submission",
        })

        if is_login:
            description = f"Auto-generated login flow for {node.url_pattern}"
            params.setdefault("test_email", "admin@test.com")
            params.setdefault("test_password", "password123")
        else:
            description = f"Auto-generated form flow for {node.url_pattern}"

        flow_data: dict[str, Any] = {
            "name": flow_name,
            "description": description,
        }
        if params:
            flow_data["params"] = params
        flow_data["steps"] = steps

        yaml_content = yaml.dump(flow_data, default_flow_style=False, sort_keys=False, allow_unicode=True)
        path.write_text(yaml_content)
        log.info("Generated flow: %s", path)
        return path

    # ── Heuristics ─────────────────────────────────────

    def _looks_like_login(self, node: PageNode, fields: list[str]) -> bool:
        """Guess if this form is a login form."""
        indicators = ["login", "signin", "sign-in", "auth"]
        url_lower = node.url_pattern.lower()
        title_lower = node.title.lower()
        if any(ind in url_lower or ind in title_lower for ind in indicators):
            return True
        field_str = " ".join(fields).lower()
        return "password" in field_str and ("email" in field_str or "user" in field_str)

    def _selector_to_param(self, selector: str) -> str:
        """Convert a CSS selector to a clean parameter name."""
        name = selector.lstrip("#.").strip("[]\"'")
        name = name.replace("name=", "").replace('"', "")
        return name.replace("-", "_").replace(".", "_")

    def _guess_field_type(self, selector: str, is_login: bool) -> str:
        s = selector.lower()
        if "password" in s:
            return "password"
        if "email" in s:
            return "email"
        return "text"

    def _find_submit_selector(self, node: PageNode, form_selector: str) -> str:
        """Find the best submit button selector for this form."""
        for btn in node.buttons:
            if btn:
                return btn
        if form_selector != "form":
            return f"{form_selector} button[type=submit]"
        return "button[type=submit]"
