import json
import importlib.util
from pathlib import Path

from sqlalchemy import create_engine, text


def _create_match_attempts_table(conn):
    conn.execute(text("""
        CREATE TABLE competitor_match_attempts (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            sku TEXT,
            source TEXT,
            attempt_status TEXT,
            momo_product_id INTEGER,
            momo_product_name TEXT,
            momo_price NUMERIC,
            candidate_count INTEGER,
            best_competitor_product_id TEXT,
            best_competitor_product_name TEXT,
            best_competitor_price NUMERIC,
            best_match_score NUMERIC,
            competitor_product_url TEXT,
            competitor_image_url TEXT,
            competitor_stock TEXT,
            diagnostic_codes TEXT,
            error_message TEXT,
            attempted_at TEXT
        )
    """))


def _load_rescore_cli_module():
    module_path = Path(__file__).resolve().parents[1] / "scripts" / "audit_competitor_match_attempt_rescore.py"
    spec = importlib.util.spec_from_file_location("audit_competitor_match_attempt_rescore_cli", module_path)
    module = importlib.util.module_from_spec(spec)
    assert spec and spec.loader
    spec.loader.exec_module(module)
    return module


def test_match_attempt_rescore_cli_defaults_to_unfiltered_reasons(monkeypatch, capsys):
    cli = _load_rescore_cli_module()
    captured = {}

    def fake_build_match_attempt_rescore_audit(_engine, **kwargs):
        captured.update(kwargs)
        return {"scanned": 0}

    monkeypatch.setattr(cli, "create_engine", lambda _database_path: object())
    monkeypatch.setattr(cli, "build_match_attempt_rescore_audit", fake_build_match_attempt_rescore_audit)

    assert cli.main(["--limit", "1"]) == 0

    capsys.readouterr()
    assert captured["reason_filter"] is None


def test_match_attempt_rescore_audit_classifies_current_gate_pass_and_veto():
    from services.competitor_match_attempt_rescore_audit import summarize_match_attempt_rescore

    rows = [
        {
            "sku": "9031334",
            "attempt_status": "true_low_confidence",
            "momo_product_name": "【Mustela 慕之恬廊】慕之幼 加量版爽身潤膚乳 500mlX2入(寶寶 嬰兒乳液 公司貨 台灣獨家總代理)",
            "best_competitor_product_name": "【慕之恬廊】慕之幼爽身潤膚乳(500毫升X2入)",
            "momo_price": 1390,
            "best_competitor_price": 1210,
            "best_match_score": 0.709,
        },
        {
            "sku": "12534698",
            "attempt_status": "true_low_confidence",
            "momo_product_name": "【LANCOME 蘭蔻】官方直營 超極光活粹晶露150ml(LANCOME/四重酸極光水/化妝水/精華水)",
            "best_competitor_product_name": "LANCOME 蘭蔻 超極限肌因精華露150ml 專櫃公司貨",
            "momo_price": 3555,
            "best_competitor_price": 1880,
            "best_match_score": 0.748,
        },
    ]

    summary = summarize_match_attempt_rescore(rows)

    assert summary["scanned"] == 2
    assert summary["gate_pass"] == 1
    assert summary["identity_veto"] == 1
    assert summary["status_counts"]["accepted_current"] == 1
    assert summary["status_counts"]["identity_veto_current"] == 1
    assert summary["samples"][0]["current_score"] >= 0.76
    assert "shared_identity_anchor_reordered_line" in summary["samples"][0]["reasons"]
    assert "lancome_line_conflict" in summary["samples"][1]["reasons"]


def test_match_attempt_rescore_audit_keeps_unit_price_cases_out_of_gate_pass():
    from services.competitor_match_attempt_rescore_audit import classify_match_attempt_row

    decision = classify_match_attempt_row({
        "sku": "12670442",
        "attempt_status": "true_low_confidence",
        "momo_product_name": "【日本Beauty Foot】去角質足膜25mlx2枚入 5入組(一般尺寸、大尺寸可選)",
        "best_competitor_product_name": "【日本Beauty Foot 】煥膚足膜(25ml*2枚入)四入組",
        "momo_price": 961,
        "best_competitor_price": 989,
        "best_match_score": 0.738,
    })

    assert decision.suggested_status == "unit_comparable_current"
    assert decision.gate_pass is False
    assert decision.comparison_mode == "unit_comparable"
    assert "unit_comparable" in decision.reasons


def test_match_attempt_rescore_audit_keeps_variant_selection_review_out_of_gate_pass():
    from services.competitor_match_attempt_rescore_audit import classify_match_attempt_row

    decision = classify_match_attempt_row({
        "sku": "8884618",
        "attempt_status": "true_low_confidence",
        "momo_product_name": "【KATE 凱婷】怪獸級持色唇膏 水光款/經典款/微發色款(獨家技術持久不沾 高保濕)",
        "best_competitor_product_name": "【KATE 凱婷】怪獸級持色唇膏(水光) 1.6g",
        "momo_price": 420,
        "best_competitor_price": 350,
        "best_match_score": 0.623,
    })

    assert decision.current_score >= 0.76
    assert decision.suggested_status == "low_score_current"
    assert decision.gate_pass is False
    assert decision.alert_tier == "identity_review"
    assert "variant_selection_review" in decision.reasons


def test_match_attempt_rescore_audit_keeps_no_match_out_of_gate_pass(monkeypatch):
    from types import SimpleNamespace

    import services.competitor_match_attempt_rescore_audit as audit

    monkeypatch.setattr(
        audit,
        "score_marketplace_match",
        lambda *_args, **_kwargs: SimpleNamespace(
            score=0.96,
            hard_veto=False,
            comparison_mode="exact_identity",
            match_type="no_match",
            price_basis="none",
            alert_tier="suppress",
            reasons=("strong_exact_spec_match",),
        ),
    )

    decision = audit.classify_match_attempt_row({
        "sku": "NO-MATCH",
        "attempt_status": "true_low_confidence",
        "momo_product_name": "MOMO candidate",
        "best_competitor_product_name": "PChome candidate",
        "momo_price": 100,
        "best_competitor_price": 90,
        "best_match_score": 0.96,
    })

    assert decision.suggested_status == "low_score_current"
    assert decision.gate_pass is False
    assert decision.match_type == "no_match"
    assert decision.price_basis == "none"
    assert decision.alert_tier == "suppress"


def test_match_attempt_rescore_audit_skips_missing_identity_text():
    from services.competitor_match_attempt_rescore_audit import classify_match_attempt_row

    decision = classify_match_attempt_row({"sku": "NO-TEXT", "attempt_status": "low_score"})

    assert decision.suggested_status == "skipped_missing_identity_text"
    assert decision.current_score is None
    assert decision.gate_pass is False


def test_fetch_match_attempt_rescore_rows_defaults_to_latest_sku_state():
    from services.competitor_match_attempt_rescore_audit import fetch_match_attempt_rescore_rows

    engine = create_engine("sqlite:///:memory:")
    with engine.begin() as conn:
        _create_match_attempts_table(conn)
        conn.execute(text("""
            INSERT INTO competitor_match_attempts
                (sku, source, attempt_status, momo_product_name, best_competitor_product_id,
                 best_competitor_product_name, best_match_score, diagnostic_codes, attempted_at)
            VALUES
                ('SKU-A', 'pchome', 'true_low_confidence', 'MOMO A', 'P-A', 'PChome A', 0.72, '["old_low"]', '2026-05-24 09:00:00'),
                ('SKU-A', 'pchome', 'rescore_accepted_current', 'MOMO A', 'P-A', 'PChome A', 0.91, '["new_queue"]', '2026-05-24 10:00:00'),
                ('SKU-B', 'pchome', 'true_low_confidence', 'MOMO B', 'P-B', 'PChome B', 0.73, '["current_low"]', '2026-05-24 11:00:00')
        """))

        latest_rows = fetch_match_attempt_rescore_rows(
            conn,
            statuses=("true_low_confidence",),
            limit=10,
        )
        historical_rows = fetch_match_attempt_rescore_rows(
            conn,
            statuses=("true_low_confidence",),
            limit=10,
            latest_sku_only=False,
        )

    assert [row["sku"] for row in latest_rows] == ["SKU-B"]
    assert {row["sku"] for row in historical_rows} == {"SKU-A", "SKU-B"}


def test_fetch_match_attempt_rescore_rows_can_limit_to_specific_skus():
    from services.competitor_match_attempt_rescore_audit import fetch_match_attempt_rescore_rows

    engine = create_engine("sqlite:///:memory:")
    with engine.begin() as conn:
        _create_match_attempts_table(conn)
        conn.execute(text("""
            INSERT INTO competitor_match_attempts
                (sku, source, attempt_status, momo_product_name, best_competitor_product_id,
                 best_competitor_product_name, best_match_score, diagnostic_codes, attempted_at)
            VALUES
                ('SKU-A', 'pchome', 'true_low_confidence', 'MOMO A', 'P-A', 'PChome A', 0.82, '["current_low"]', '2026-05-24 09:00:00'),
                ('SKU-B', 'pchome', 'true_low_confidence', 'MOMO B', 'P-B', 'PChome B', 0.83, '["current_low"]', '2026-05-24 10:00:00'),
                ('SKU-C', 'pchome', 'true_low_confidence', 'MOMO C', 'P-C', 'PChome C', 0.84, '["current_low"]', '2026-05-24 11:00:00')
        """))

        rows = fetch_match_attempt_rescore_rows(
            conn,
            statuses=("true_low_confidence",),
            skus=("SKU-A", "SKU-C"),
            limit=10,
        )

    assert [row["sku"] for row in rows] == ["SKU-C", "SKU-A"]


def test_match_attempt_rescore_materializes_accepted_current_for_manual_review():
    from services.competitor_match_attempt_rescore_audit import materialize_rescore_accept_reviews

    engine = create_engine("sqlite:///:memory:")
    rows = [{
        "sku": "9031334",
        "attempt_status": "true_low_confidence",
        "momo_product_id": 9031334,
        "momo_product_name": "【Mustela 慕之恬廊】慕之幼 加量版爽身潤膚乳 500mlX2入(寶寶 嬰兒乳液 公司貨 台灣獨家總代理)",
        "momo_price": 1390,
        "candidate_count": 1,
        "best_competitor_product_id": "DDAXS-A900IHGY",
        "best_competitor_product_name": "【慕之恬廊】慕之幼爽身潤膚乳(500毫升X2入)",
        "best_competitor_price": 1210,
        "best_match_score": 0.709,
    }]

    with engine.begin() as conn:
        stats = materialize_rescore_accept_reviews(conn, rows)
        duplicate_stats = materialize_rescore_accept_reviews(conn, rows)
        stored = conn.execute(text("""
            SELECT attempt_status, best_match_score, search_terms,
                   match_diagnostic_json, diagnostic_codes, error_message
            FROM competitor_match_attempts
        """)).mappings().all()

    assert stats["materialized"] == 1
    assert duplicate_stats["skipped_duplicate"] == 1
    assert len(stored) == 1
    assert stored[0]["attempt_status"] == "rescore_accepted_current"
    assert float(stored[0]["best_match_score"]) >= 0.76
    assert "matcher_rescore:accepted_current" in json.loads(stored[0]["search_terms"])
    assert "shared_identity_anchor_reordered_line" in json.loads(stored[0]["diagnostic_codes"])
    payload = json.loads(stored[0]["match_diagnostic_json"])
    assert payload["stored_status"] == "true_low_confidence"
    assert payload["price_basis"] == "manual_review"
    assert "matcher_rescore=accepted_current" in stored[0]["error_message"]


def test_match_attempt_rescore_materialize_allows_requeue_when_latest_is_low_confidence():
    from services.competitor_match_attempt_rescore_audit import materialize_rescore_accept_reviews

    engine = create_engine("sqlite:///:memory:")
    rows = [{
        "sku": "10509765",
        "attempt_status": "true_low_confidence",
        "momo_product_id": 10509765,
        "momo_product_name": "【悠斯晶】經典乳霜120g(2入組)",
        "momo_price": 599,
        "candidate_count": 1,
        "best_competitor_product_id": "YUSKIN-120G-2",
        "best_competitor_product_name": "【Yuskin悠斯晶】經典乳霜 2盒組(120g/盒)",
        "best_competitor_price": 540,
        "best_match_score": 0.779,
    }]

    with engine.begin() as conn:
        initial_stats = materialize_rescore_accept_reviews(conn, rows)
        duplicate_stats = materialize_rescore_accept_reviews(conn, rows)
        conn.execute(text("""
            INSERT INTO competitor_match_attempts
                (sku, source, attempt_status, momo_product_id, momo_product_name,
                 momo_price, candidate_count, best_competitor_product_id,
                 best_competitor_product_name, best_competitor_price,
                 best_match_score, diagnostic_codes, error_message, attempted_at)
            VALUES
                ('10509765', 'pchome', 'true_low_confidence', 10509765,
                 '【悠斯晶】經典乳霜120g(2入組)', 599, 1, 'YUSKIN-120G-2',
                 '【Yuskin悠斯晶】經典乳霜 2盒組(120g/盒)', 540, 0.779,
                 '["strong_exact_spec_match"]', 'later crawler low-confidence row',
                 CURRENT_TIMESTAMP)
        """))
        requeue_stats = materialize_rescore_accept_reviews(conn, rows)
        latest_status = conn.execute(text("""
            SELECT attempt_status
            FROM competitor_match_attempts
            WHERE sku = '10509765'
            ORDER BY attempted_at DESC, id DESC
            LIMIT 1
        """)).scalar_one()

    assert initial_stats["materialized"] == 1
    assert duplicate_stats["skipped_duplicate"] == 1
    assert requeue_stats["materialized"] == 1
    assert requeue_stats["skipped_duplicate"] == 0
    assert latest_status == "rescore_accepted_current"


def test_match_attempt_rescore_retracts_variant_review_from_accepted_queue():
    from services.competitor_match_attempt_rescore_audit import (
        fetch_variant_rescore_accept_review_rows,
        retract_variant_rescore_accept_reviews,
    )

    engine = create_engine("sqlite:///:memory:")
    with engine.begin() as conn:
        _create_match_attempts_table(conn)
        conn.execute(text("""
            INSERT INTO competitor_match_attempts
                (sku, source, attempt_status, momo_product_id, momo_product_name,
                 momo_price, candidate_count, best_competitor_product_id,
                 best_competitor_product_name, best_competitor_price,
                 best_match_score, diagnostic_codes, error_message, attempted_at)
            VALUES
                (
                    '8884618', 'pchome', 'rescore_accepted_current', 8884618,
                    '【KATE 凱婷】怪獸級持色唇膏 水光款/經典款/微發色款(獨家技術持久不沾 高保濕)',
                    420, 1, 'KATE-WATER',
                    '【KATE 凱婷】怪獸級持色唇膏(水光) 1.6g',
                    350, 0.783,
                    '["variant_selection_review", "focused_exact_identity_kate_monster_lipstick_catalog"]',
                    'matcher_rescore=accepted_current', '2026-05-24 14:24:17'
                ),
                (
                    '10922465', 'pchome', 'rescore_accepted_current', 10922465,
                    '【Herbacin 德國小甘菊】小甘菊1號護手霜20ml',
                    99, 1, 'HERBACIN-20ML',
                    '小甘菊經典護手霜20ml',
                    89, 0.872,
                    '["focused_exact_identity_herbacin_classic_hand_cream_20ml_brandless"]',
                    'matcher_rescore=accepted_current', '2026-05-24 14:24:17'
                ),
                (
                    '10524966', 'pchome', 'rescore_accepted_current', 10524966,
                    '【Derma 丹麥德瑪】寶寶有機水嫩洗髮沐浴露 150ml(寶寶沐浴、嬰兒沐浴)',
                    399, 1, 'DERMA-150ML',
                    'Derma 寶寶洗髮沐浴露 150ml',
                    349, 0.82,
                    '["strong_exact_spec_match", "spec_name_alignment"]',
                    'matcher_rescore=accepted_current', '2026-05-24 14:24:17'
                )
        """))

        rows = fetch_variant_rescore_accept_review_rows(conn, limit=10)
        stats = retract_variant_rescore_accept_reviews(conn, rows)
        latest = conn.execute(text("""
            WITH ranked AS (
                SELECT sku, attempt_status, search_terms, error_message,
                       diagnostic_codes, attempted_at,
                       ROW_NUMBER() OVER (
                           PARTITION BY sku
                           ORDER BY attempted_at DESC, id DESC
                       ) AS rn
                FROM competitor_match_attempts
                WHERE source = 'pchome'
            )
            SELECT *
            FROM ranked
            WHERE rn = 1
            ORDER BY sku
        """)).mappings().all()
        after_rows = fetch_variant_rescore_accept_review_rows(conn, limit=10)

    assert [row["sku"] for row in rows] == ["10922465", "8884618"]
    assert stats["retracted"] == 2
    latest_by_sku = {row["sku"]: row for row in latest}
    assert latest_by_sku["8884618"]["attempt_status"] == "true_low_confidence"
    assert "matcher_rescore:retracted_variant_selection_review" in json.loads(
        latest_by_sku["8884618"]["search_terms"]
    )
    assert "rescore_retracted_variant_selection_review" in latest_by_sku["8884618"]["error_message"]
    assert latest_by_sku["10922465"]["attempt_status"] == "true_low_confidence"
    assert latest_by_sku["10524966"]["attempt_status"] == "rescore_accepted_current"
    assert after_rows == []


def test_match_attempt_rescore_retracts_unsafe_accepted_queue(monkeypatch):
    from types import SimpleNamespace

    import services.competitor_match_attempt_rescore_audit as audit

    engine = create_engine("sqlite:///:memory:")
    with engine.begin() as conn:
        _create_match_attempts_table(conn)
        conn.execute(text("""
            INSERT INTO competitor_match_attempts
                (sku, source, attempt_status, momo_product_id, momo_product_name,
                 momo_price, candidate_count, best_competitor_product_id,
                 best_competitor_product_name, best_competitor_price,
                 best_match_score, diagnostic_codes, error_message, attempted_at)
            VALUES
                (
                    'NO-MATCH', 'pchome', 'rescore_accepted_current', 1,
                    'MOMO candidate',
                    100, 1, 'PCHOME-NO-MATCH',
                    'PChome candidate',
                    90, 0.96,
                    '["strong_exact_spec_match"]',
                    'matcher_rescore=accepted_current', '2026-05-24 14:24:17'
                )
        """))

        monkeypatch.setattr(
            audit,
            "score_marketplace_match",
            lambda *_args, **_kwargs: SimpleNamespace(
                score=0.96,
                hard_veto=False,
                comparison_mode="exact_identity",
                match_type="no_match",
                price_basis="none",
                alert_tier="suppress",
                reasons=("strong_exact_spec_match",),
            ),
        )

        rows = audit.fetch_unsafe_rescore_accept_review_rows(conn, limit=10)
        stats = audit.retract_unsafe_rescore_accept_reviews(conn, rows)
        latest_status = conn.execute(text("""
            SELECT attempt_status
            FROM competitor_match_attempts
            WHERE sku = 'NO-MATCH'
            ORDER BY attempted_at DESC, id DESC
            LIMIT 1
        """)).scalar()
        error_message = conn.execute(text("""
            SELECT error_message
            FROM competitor_match_attempts
            WHERE sku = 'NO-MATCH'
            ORDER BY attempted_at DESC, id DESC
            LIMIT 1
        """)).scalar()

    assert [row["sku"] for row in rows] == ["NO-MATCH"]
    assert stats["retracted"] == 1
    assert latest_status == "true_low_confidence"
    assert "rescore_retracted_unsafe_accepted_current" in error_message


def test_match_attempt_rescore_materialize_does_not_enqueue_veto():
    from services.competitor_match_attempt_rescore_audit import materialize_rescore_accept_reviews

    engine = create_engine("sqlite:///:memory:")
    rows = [{
        "sku": "12534698",
        "attempt_status": "true_low_confidence",
        "momo_product_name": "【LANCOME 蘭蔻】官方直營 超極光活粹晶露150ml(LANCOME/四重酸極光水/化妝水/精華水)",
        "best_competitor_product_id": "LANCOME-BAD",
        "best_competitor_product_name": "LANCOME 蘭蔻 超極限肌因精華露150ml 專櫃公司貨",
        "momo_price": 3555,
        "best_competitor_price": 1880,
        "best_match_score": 0.748,
    }]

    with engine.begin() as conn:
        stats = materialize_rescore_accept_reviews(conn, rows)
        row_count = conn.execute(text("SELECT COUNT(*) FROM competitor_match_attempts")).scalar()

    assert stats["materialized"] == 0
    assert stats["skipped_not_gate_pass"] == 1
    assert row_count == 0
