"""analyze_test_patterns MCP tool.

Standalone tool that analyzes historical test results to extract proven patterns
(selectors, navigation sequences, assertions) from passing tests. Saves to a
persistent cache that generate_tests reads automatically.
"""

import json
import os
from pathlib import Path

from mcp.types import TextContent, Tool

import structlog

logger = structlog.get_logger()


def analyze_test_patterns_tool() -> Tool:
    """Return the tool definition for analyze_test_patterns."""
    return Tool(
        name="analyze_test_patterns",
        description=(
            "Analyze historical test results to extract proven patterns (selectors, "
            "navigation sequences, assertions) from passing tests. Saves patterns to "
            "a cache that generate_tests reads automatically to generate better, more "
            "reliable tests. Call this before generating tests, or after running tests "
            "to learn from new results."
        ),
        inputSchema={
            "type": "object",
            "properties": {
                "target_path": {
                    "type": "string",
                    "description": (
                        "Absolute path to the repo root. Defaults to server working directory."
                    ),
                },
                "force_refresh": {
                    "type": "boolean",
                    "description": "Force full re-analysis even if cache is fresh.",
                },
            },
        },
    )


async def handle_analyze_test_patterns(arguments: dict) -> list[TextContent]:
    """Handle the analyze_test_patterns tool call."""
    from maeris_mcp.auth.token_store import TokenStore
    from maeris_mcp.maeris.client import MaerisClient
    from maeris_mcp.storage.feedback_cache import RepoFeedbackCache
    from maeris_mcp.analysis.feedback_analyzer import analyze_test_results
    from maeris_mcp.tools.code_map_tool import codemap_path_for, codemap_content_hash

    # --- Validate auth ---
    try:
        token_store = TokenStore()
        app_id = token_store.get_app_id()
        if not app_id:
            return [TextContent(
                type="text",
                text="Error: No application selected. Use `switch_application` first.",
            )]
    except Exception as e:
        return [TextContent(
            type="text",
            text=f"Error: Not authenticated. Please `login` first. ({e})",
        )]

    # --- Resolve target path ---
    target_path = arguments.get("target_path") or os.getcwd()
    target_path = str(Path(target_path).resolve())
    force_refresh = arguments.get("force_refresh", False)

    # --- Load cache ---
    cache = RepoFeedbackCache(target_path, app_id)
    entry = cache.load()

    # --- Compute codemap hash ---
    cm_path = codemap_path_for(target_path)
    cm_hash = codemap_content_hash(cm_path)

    # --- Determine analysis type ---
    async with MaerisClient() as client:
        testcases = await client.get_testcases()
        tc_count = len(testcases) if testcases else 0

        if tc_count == 0:
            return [TextContent(
                type="text",
                text="No testcases found for the current application. Nothing to analyze.",
            )]

        # Get latest result timestamp for incremental check
        tc_ids = [
            tc.get("_id") or tc.get("id") or tc.get("testcase_id") or ""
            for tc in testcases
            if tc.get("_id") or tc.get("id") or tc.get("testcase_id")
        ]
        latest_result_ts = ""
        if tc_ids:
            try:
                # Quick check: get results for first few to find latest timestamp
                sample_ids = tc_ids[:10]
                sample_results = await client.get_test_results_for_testcases(sample_ids)
                for results in sample_results.values():
                    for r in results:
                        ts = r.get("created_at") or ""
                        if ts and ts > latest_result_ts:
                            latest_result_ts = ts
            except Exception:
                pass

        # Decide analysis type
        if force_refresh:
            analysis_type = "full (forced)"
            incremental = False
        elif cache.is_stale(tc_count, cm_hash):
            analysis_type = "full (cache stale)"
            incremental = False
        elif cache.needs_incremental_update(latest_result_ts):
            analysis_type = "incremental (new results)"
            incremental = True
        else:
            # Cache is fresh — return summary
            summary = _build_summary(entry, "cached (fresh)")
            return [TextContent(type="text", text=summary)]

        # --- Run analysis ---
        logger.info(
            "feedback_tool.analyzing",
            analysis_type=analysis_type,
            testcase_count=tc_count,
        )

        await analyze_test_results(
            client=client,
            cache=cache,
            incremental=incremental,
            codemap_hash=cm_hash,
        )

    # Reload after analysis
    entry = cache.load()
    summary = _build_summary(entry, analysis_type)
    return [TextContent(type="text", text=summary)]


def _build_summary(entry, analysis_type: str) -> str:
    """Build a human-readable summary of the feedback cache."""
    lines = [
        f"## Test Pattern Analysis ({analysis_type})",
        "",
        f"- **Testcases analyzed:** {entry.testcase_count_at_analysis}",
        f"- **Proven selectors:** {len(entry.proven_selectors)}",
        f"- **Navigation sequences:** {len(entry.proven_nav_sequences)}",
        f"- **Assertion patterns:** {len(entry.assertion_patterns)}",
        f"- **Pages tracked:** {len(entry.page_pass_rates)}",
        f"- **Flaky selectors:** {len(entry.flaky_selectors)}",
    ]

    if entry.proven_selectors:
        lines.append("")
        lines.append("### Top Proven Selectors")
        for s in entry.proven_selectors[:10]:
            lines.append(
                f"  - `{s.get('selector', '')}` → {s.get('action', '')} "
                f"@ {s.get('page_url', '')} [{s.get('pass_count', 0)} passes]"
            )

    if entry.flaky_selectors:
        lines.append("")
        lines.append("### Flaky Selectors (avoid)")
        for f in entry.flaky_selectors[:5]:
            lines.append(
                f"  - `{f.get('selector', '')}` @ {f.get('page_url', '')} "
                f"[{f.get('flakiness_score', 0):.0f}% flaky]"
            )

    if entry.page_pass_rates:
        lines.append("")
        lines.append("### Page Reliability")
        for page, rates in sorted(
            entry.page_pass_rates.items(),
            key=lambda x: x[1].get("rate", 0),
            reverse=True,
        )[:10]:
            lines.append(
                f"  - {page}: {rates.get('rate', 0):.0f}% "
                f"({rates.get('passed', 0)}/{rates.get('total', 0)})"
            )

    lines.append("")
    lines.append("These patterns will be automatically used by `generate_tests`.")
    return "\n".join(lines)
