from pathlib import Path

from auraindex.models import IndexSuggestion, ParsedQueryFeatures, QueryCandidate, QueryContext, ScanResult, WorkloadStats
from auraindex.pipeline import ScanConfig, run_scan
from auraindex.reporting import build_report_dict, render_html_report, render_markdown_report


def test_report_dict_includes_detailed_index_evidence_fields(tmp_path: Path) -> None:
    sample = tmp_path / "queries.sql"
    sample.write_text(
        """
SELECT id FROM users WHERE status = 'active' ORDER BY created_at DESC;
SELECT id FROM users WHERE status = 'active';
""".strip(),
        encoding="utf-8",
    )

    result = run_scan(
        ScanConfig(
            target_path=tmp_path,
            dialect="postgres",
            min_support=1,
            max_indexes_per_table=4,
            extensions={".sql"},
        )
    )
    report = build_report_dict(
        result,
        dialect="postgres",
        config={"path": str(tmp_path), "extensions": [".sql"]},
    )

    details = report["detailed_index_evidence"]
    assert isinstance(details, dict)
    assert details
    first = next(iter(details.values()))
    assert "support_count" in first
    assert "matched_query_count" in first
    assert "matched_queries" in first
    assert isinstance(first["matched_queries"], list)


def test_html_report_contains_copy_controls_and_trace_sections(tmp_path: Path) -> None:
    sample = tmp_path / "queries.sql"
    sample.write_text(
        """
SELECT id FROM users WHERE status = 'active' ORDER BY created_at DESC;
SELECT id FROM users WHERE status = 'active';
""".strip(),
        encoding="utf-8",
    )

    result = run_scan(
        ScanConfig(
            target_path=tmp_path,
            dialect="postgres",
            min_support=1,
            max_indexes_per_table=4,
            extensions={".sql"},
        )
    )
    html = render_html_report(
        result,
        dialect="postgres",
        config={"path": str(tmp_path), "extensions": [".sql"]},
    )

    assert "copyFromId" in html
    assert "support count" in html
    assert "Matched query excerpts" in html
    assert "How to read ranked table columns" in html
    assert 'datalist id="index-search-options"' in html
    assert "function applyQuickFilter" in html
    assert "class='rank-row'" in html
    assert "table:users" in html


def test_html_report_resolves_relative_target_path_to_absolute(tmp_path: Path) -> None:
    sample = tmp_path / "queries.sql"
    sample.write_text("SELECT id FROM users WHERE status = 'active';", encoding="utf-8")
    result = run_scan(
        ScanConfig(
            target_path=tmp_path,
            dialect="postgres",
            min_support=1,
            max_indexes_per_table=4,
            extensions={".sql"},
        )
    )

    html = render_html_report(
        result,
        dialect="postgres",
        config={"path": ".", "extensions": [".sql"]},
    )

    assert "Target path (absolute):" in html
    assert str(Path(".").resolve()) in html
    assert "Target path (absolute): ." not in html


def test_html_report_places_ranked_section_before_schema_summary(tmp_path: Path) -> None:
    sample = tmp_path / "queries.sql"
    sample.write_text(
        """
SELECT id FROM users WHERE status = 'active' ORDER BY created_at DESC;
SELECT id FROM users WHERE status = 'active';
""".strip(),
        encoding="utf-8",
    )
    result = run_scan(
        ScanConfig(
            target_path=tmp_path,
            dialect="postgres",
            min_support=1,
            max_indexes_per_table=4,
            extensions={".sql"},
        )
    )
    result.metadata = {
        "schema_checks": {
            "summary": {
                "discovered_existing_indexes": 2,
                "kept_suggestions": 1,
                "skipped_suggestions": 1,
            }
        }
    }
    html = render_html_report(
        result,
        dialect="postgres",
        config={"path": str(tmp_path), "extensions": [".sql"]},
    )

    assert html.index("Ranked Suggestions") < html.index("Schema-aware checks")


def test_report_dedupes_adjacent_wasm_duplicate_lines() -> None:
    sql = "SELECT id FROM users WHERE users.status = ?"
    query_a = QueryCandidate(
        sql=sql,
        context=QueryContext(
            file_path="sample.py",
            line=10,
            function=None,
            language="python",
            source_kind="wasm_sql",
        ),
        confidence=0.82,
    )
    query_b = QueryCandidate(
        sql=sql,
        context=QueryContext(
            file_path="sample.py",
            line=11,
            function=None,
            language="python",
            source_kind="wasm_sql",
        ),
        confidence=0.82,
    )
    parsed_a = ParsedQueryFeatures(
        query=query_a,
        statement_kind="select",
        tables=["users"],
        where_columns=[("users", "status")],
        join_columns=[],
        order_by_columns=[],
        group_by_columns=[],
        equality_columns_by_table={"users": ["status"]},
    )
    parsed_b = ParsedQueryFeatures(
        query=query_b,
        statement_kind="select",
        tables=["users"],
        where_columns=[("users", "status")],
        join_columns=[],
        order_by_columns=[],
        group_by_columns=[],
        equality_columns_by_table={"users": ["status"]},
    )
    suggestion = IndexSuggestion(
        table="users",
        columns=["status"],
        index_name="ix_users_status",
        kind="filter_key",
        score=6.0,
        confidence=0.8,
        reason="Column `status` is used in WHERE predicates.",
        evidence={"support_count": 2, "where_count": 2},
        ddl='CREATE INDEX IF NOT EXISTS "ix_users_status" ON "users" ("status");',
        needs_manual_review=True,
        orm_snippets={"sqlalchemy": 'Index("ix_users_status", users.c.status)', "django": ""},
    )
    result = ScanResult(
        scanned_files=["sample.py"],
        candidates=[query_a, query_b],
        parsed_queries=[parsed_a, parsed_b],
        parse_failures=[],
        workload=WorkloadStats(total_queries=2, table_query_count={"users": 2}),
        suggestions=[suggestion],
        warnings=[],
    )

    report = build_report_dict(result, dialect="postgres", config={"path": ".", "extensions": [".py"]})
    evidence = report["detailed_index_evidence"]["ix_users_status"]
    assert evidence["matched_query_count"] == 1
    assert evidence["supporting_contexts"] == ["sample.py:10 (<module>)"]


def test_report_keeps_adjacent_non_wasm_queries() -> None:
    sql = "SELECT id FROM users WHERE status = 'active'"
    query_a = QueryCandidate(
        sql=sql,
        context=QueryContext(
            file_path="queries.sql",
            line=1,
            function=None,
            language="sql",
            source_kind="sql_file",
        ),
        confidence=1.0,
    )
    query_b = QueryCandidate(
        sql=sql,
        context=QueryContext(
            file_path="queries.sql",
            line=2,
            function=None,
            language="sql",
            source_kind="sql_file",
        ),
        confidence=1.0,
    )
    parsed_a = ParsedQueryFeatures(
        query=query_a,
        statement_kind="select",
        tables=["users"],
        where_columns=[("users", "status")],
        join_columns=[],
        order_by_columns=[],
        group_by_columns=[],
        equality_columns_by_table={"users": ["status"]},
    )
    parsed_b = ParsedQueryFeatures(
        query=query_b,
        statement_kind="select",
        tables=["users"],
        where_columns=[("users", "status")],
        join_columns=[],
        order_by_columns=[],
        group_by_columns=[],
        equality_columns_by_table={"users": ["status"]},
    )
    suggestion = IndexSuggestion(
        table="users",
        columns=["status"],
        index_name="ix_users_status",
        kind="filter_key",
        score=6.0,
        confidence=0.8,
        reason="Column `status` is used in WHERE predicates.",
        evidence={"support_count": 2, "where_count": 2},
        ddl='CREATE INDEX IF NOT EXISTS "ix_users_status" ON "users" ("status");',
        needs_manual_review=True,
        orm_snippets={"sqlalchemy": 'Index("ix_users_status", users.c.status)', "django": ""},
    )
    result = ScanResult(
        scanned_files=["queries.sql"],
        candidates=[query_a, query_b],
        parsed_queries=[parsed_a, parsed_b],
        parse_failures=[],
        workload=WorkloadStats(total_queries=2, table_query_count={"users": 2}),
        suggestions=[suggestion],
        warnings=[],
    )

    report = build_report_dict(result, dialect="postgres", config={"path": ".", "extensions": [".sql"]})
    evidence = report["detailed_index_evidence"]["ix_users_status"]
    assert evidence["matched_query_count"] == 2


def test_markdown_report_shows_all_ranked_suggestions_by_default() -> None:
    suggestion_a = IndexSuggestion(
        table="users",
        columns=["status"],
        index_name="ix_users_status",
        kind="filter_key",
        score=9.0,
        confidence=0.86,
        reason="status is frequently filtered",
        evidence={"support_count": 5, "where_count": 5},
        ddl='CREATE INDEX IF NOT EXISTS "ix_users_status" ON "users" ("status");',
        needs_manual_review=False,
        orm_snippets={"sqlalchemy": 'Index("ix_users_status", users.c.status)', "django": ""},
    )
    suggestion_b = IndexSuggestion(
        table="users",
        columns=["created_at"],
        index_name="ix_users_created_at",
        kind="order_key",
        score=8.2,
        confidence=0.81,
        reason="created_at appears in ORDER BY",
        evidence={"support_count": 4, "order_count": 4},
        ddl='CREATE INDEX IF NOT EXISTS "ix_users_created_at" ON "users" ("created_at");',
        needs_manual_review=False,
        orm_snippets={"sqlalchemy": 'Index("ix_users_created_at", users.c.created_at)', "django": ""},
    )
    result = ScanResult(
        scanned_files=["queries.sql"],
        candidates=[],
        parsed_queries=[],
        parse_failures=[],
        workload=WorkloadStats(total_queries=0),
        suggestions=[suggestion_a, suggestion_b],
        warnings=[],
    )

    markdown = render_markdown_report(
        result,
        dialect="postgres",
        config={"path": ".", "extensions": [".sql"]},
    )

    assert "| 1 | `users` | `status` |" in markdown
    assert "| 2 | `users` | `created_at` |" in markdown
    assert "--limit-suggestions" not in markdown


def test_markdown_report_respects_suggestion_limit_flag() -> None:
    suggestion_a = IndexSuggestion(
        table="users",
        columns=["status"],
        index_name="ix_users_status",
        kind="filter_key",
        score=9.0,
        confidence=0.86,
        reason="status is frequently filtered",
        evidence={"support_count": 5, "where_count": 5},
        ddl='CREATE INDEX IF NOT EXISTS "ix_users_status" ON "users" ("status");',
        needs_manual_review=False,
        orm_snippets={"sqlalchemy": 'Index("ix_users_status", users.c.status)', "django": ""},
    )
    suggestion_b = IndexSuggestion(
        table="users",
        columns=["created_at"],
        index_name="ix_users_created_at",
        kind="order_key",
        score=8.2,
        confidence=0.81,
        reason="created_at appears in ORDER BY",
        evidence={"support_count": 4, "order_count": 4},
        ddl='CREATE INDEX IF NOT EXISTS "ix_users_created_at" ON "users" ("created_at");',
        needs_manual_review=False,
        orm_snippets={"sqlalchemy": 'Index("ix_users_created_at", users.c.created_at)', "django": ""},
    )
    result = ScanResult(
        scanned_files=["queries.sql"],
        candidates=[],
        parsed_queries=[],
        parse_failures=[],
        workload=WorkloadStats(total_queries=0),
        suggestions=[suggestion_a, suggestion_b],
        warnings=[],
    )

    markdown = render_markdown_report(
        result,
        dialect="postgres",
        config={"path": ".", "extensions": [".sql"]},
        suggestion_limit=1,
    )

    assert "Showing **1** of **2** suggestions (`--limit-suggestions`)." in markdown
    assert "| 1 | `users` | `status` |" in markdown
    assert "| 2 | `users` | `created_at` |" not in markdown
