from __future__ import annotations

from jarvis_finance.services.budget_categories import confirm_create_category
from jarvis_finance.services.budget_imports import (
    apply_user_budget_rules_to_candidates,
    create_candidate_split,
    list_transaction_candidates,
    seed_credit_card_candidates_from_rows,
    seed_migros_candidates_from_rows,
    update_transaction_candidate_category,
)
from jarvis_finance.storage.database import connect_memory
from jarvis_finance.storage.migrations import apply_migrations, get_schema_version


def db():
    conn = connect_memory()
    apply_migrations(conn)
    return conn


def add_categories(conn):
    names = [
        "Essen & Haushalt",
        "Hausrat / Möbel & Garten",
        "Freizeit / Ausflüge / Abos",
        "Gesundheit / Medizin",
        "Auto / Transport",
        "Shopping / Kleidung & Elektronik",
        "Haustiere",
        "Sonstiges / Administration",
    ]
    ids = {}
    for idx, name in enumerate(names):
        ids[name] = confirm_create_category(conn, {"name": name, "category_type": "expense", "sort_order": idx})["entity_id"]
    return ids


def row(description: str, amount: str = "12.00", date: str = "2026-02-03") -> dict[str, str]:
    return {"Datum": date, "Beschreibung": description, "Betrag": amount}


def candidate(conn, description: str):
    return conn.execute(
        "SELECT * FROM budget_transaction_candidates WHERE description=? ORDER BY created_at DESC LIMIT 1",
        (description,),
    ).fetchone()


def test_phase16_schema_adds_rule_name_and_applies_card_category_rules() -> None:
    conn = db()
    assert get_schema_version(conn) == 41
    cats = add_categories(conn)
    seed_credit_card_candidates_from_rows(
        conn,
        [
            row("Apple.com"),
            row("Google"),
            row("Amazon Prime"),
            row("Netflix"),
            row("Disney Plus"),
            row("Digitec Galaxus AG"),
            row("Kantonsspital Baden"),
            row("Apotheke Suessbach AG"),
            row("Agrola Tankstelle"),
            row("EasyPark"),
            row("SBB CFF FFS"),
            row("IKEA"),
            row("JUMBO"),
            row("Landi"),
            row("QUALIPET"),
            row("Fressnapf"),
            row("Kleintierpraxis Tim"),
            row("Dropbox"),
            row("Gemeinde Windisch"),
            row("McDonald's"),
        ],
        source_file_label="phase16_card.csv",
        subscription_category_id=cats["Freizeit / Ausflüge / Abos"],
    )

    result = apply_user_budget_rules_to_candidates(conn, year="2026")

    assert result["productive_confirmed_count"] == 0
    assert result["subscription_count"] == 5
    for desc in ["Apple.com", "Google", "Amazon Prime", "Netflix", "Disney Plus"]:
        assert candidate(conn, desc)["proposed_category_name"] == "Freizeit / Ausflüge / Abos"
        assert candidate(conn, desc)["status"] == "auto_categorized"
        assert candidate(conn, desc)["rule_name"]
    assert candidate(conn, "Digitec Galaxus AG")["status"] == "needs_review"
    assert candidate(conn, "Digitec Galaxus AG")["review_reason"] == "Galaxus/Digitec bitte manuell prüfen oder splitten"
    for desc in ["Kantonsspital Baden", "Apotheke Suessbach AG"]:
        assert candidate(conn, desc)["proposed_category_name"] == "Gesundheit / Medizin"
    for desc in ["Agrola Tankstelle", "EasyPark", "SBB CFF FFS"]:
        assert candidate(conn, desc)["proposed_category_name"] == "Auto / Transport"
    for desc in ["IKEA", "JUMBO", "Landi"]:
        assert candidate(conn, desc)["proposed_category_name"] == "Hausrat / Möbel & Garten"
    for desc in ["QUALIPET", "Fressnapf", "Kleintierpraxis Tim"]:
        assert candidate(conn, desc)["proposed_category_name"] == "Haustiere"
    for desc in ["Dropbox", "Gemeinde Windisch"]:
        assert candidate(conn, desc)["proposed_category_name"] == "Sonstiges / Administration"
    assert candidate(conn, "McDonald's")["proposed_category_name"] == "Essen & Haushalt"
    assert len(list_transaction_candidates(conn, tab="subscriptions")) == 5
    assert len(list_transaction_candidates(conn, tab="health")) == 2
    assert len(list_transaction_candidates(conn, tab="auto_transport")) == 3
    assert len(list_transaction_candidates(conn, tab="pets")) == 3


def test_phase16_migros_and_review_filters_keep_confirm_boundary_and_edits() -> None:
    conn = db()
    cats = add_categories(conn)
    seed_credit_card_candidates_from_rows(conn, [row("Migros MMM")], source_file_label="phase16_card.csv")
    seed_migros_candidates_from_rows(
        conn,
        [
            {"Datum": "2026-02-03", "Zeit": "10:00", "Filiale": "Migros Baden", "Kasse": "1", "Transaktion": "A", "Artikel": "A", "Umsatz": "10.00"},
            {"Datum": "2026-02-04", "Zeit": "11:00", "Filiale": "Migros Baden", "Kasse": "1", "Transaktion": "B", "Artikel": "B", "Umsatz": "60.00"},
        ],
        source_file_label="phase16_migros.csv",
        auto_category_id=cats["Essen & Haushalt"],
    )

    result = apply_user_budget_rules_to_candidates(conn, year="2026")

    assert result["covered_by_migros_count"] == 1
    assert result["migros_under_50_count"] == 2
    assert result["migros_over_50_count"] == 0
    covered = list_transaction_candidates(conn, tab="covered_by_migros")
    assert len(covered) == 1
    assert covered[0]["status"] == "covered_by_migros"
    assert len(list_transaction_candidates(conn, tab="migros_over_50")) == 0
    assert len(list_transaction_candidates(conn, tab="auto")) == 2

    auto = list_transaction_candidates(conn, tab="auto")[0]
    update_transaction_candidate_category(conn, auto["transaction_candidate_id"], cats["Hausrat / Möbel & Garten"], note="test override")
    create_candidate_split(conn, auto["transaction_candidate_id"], [{"category_id": cats["Essen & Haushalt"], "amount_original": "5.00", "notes": "part"}])
    assert conn.execute("SELECT COUNT(*) c FROM budget_transactions").fetchone()["c"] == 0
