from __future__ import annotations

from jarvis_finance.services.budget_accounts import confirm_create_budget_account
from jarvis_finance.services.budget_categories import confirm_create_category
from jarvis_finance.services.budget_import_upload import (
    confirm_uploaded_budget_import_candidates,
    get_budget_import_session,
    list_budget_import_sessions,
    preview_uploaded_budget_import,
)
from jarvis_finance.services.budget_imports import list_transaction_candidates, review_candidate_summary
from jarvis_finance.services.budget_monthly_import import get_monthly_import_dashboard
from jarvis_finance.storage.database import connect_memory
from jarvis_finance.storage.migrations import apply_migrations


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


def setup_base(conn):
    account = confirm_create_budget_account(conn, {"name": "Budget Konto", "account_type": "cash", "currency": "CHF"})["entity_id"]
    expense = confirm_create_category(conn, {"name": "Essen & Haushalt", "category_type": "expense"})["entity_id"]
    income = confirm_create_category(conn, {"name": "Lohn Marcel", "category_type": "income"})["entity_id"]
    return account, expense, income


VISA_CSV = "TransactionId,CardId,Date,Amount,Currency,MerchantName,Details\nT1,C1,2026-05-01,-10.00,CHF,Netflix,Abo\n"
MIGROS_CSV = "Datum;Zeit;Filiale;Kassennummer;Transaktionsnummer;Artikel;Menge;Aktion;Umsatz\n02.05.2026;10:00;Migros Test;1;99;Artikel;1;;1.00\n"
RAIFFEISEN_CSV = "IBAN;Booked At;Text;Credit/Debit Amount;Balance;Valuta Date\nCH1;2026-05-03;Lohn Marcel;40.00;0;2026-05-03\n"
AKB_CSV = "Buchung;Valuta;Buchungstext;Belastung;Gutschrift;Saldo CHF\n03.05.2026;03.05.2026;Lohn Marcel;;20.00;0\n"


def test_upload_preview_detects_supported_profiles_without_writing_candidates() -> None:
    conn = db(); _account, expense, income = setup_base(conn)
    cases = [
        ("visa.csv", VISA_CSV, "visa_credit_card"),
        ("migros.csv", MIGROS_CSV, "migros_receipts"),
        ("raiffeisen.csv", RAIFFEISEN_CSV, "raiffeisen_bank"),
        ("akb.csv", AKB_CSV, "akb_bank"),
    ]

    for filename, csv_text, profile in cases:
        result = preview_uploaded_budget_import(conn, filename=filename, csv_text=csv_text, profile="auto", default_category_id=expense, income_category_id=income)
        assert result["status"] == "dry_run"
        assert result["profile"] == profile
        assert result["file"]["detected"] is True
        assert result["totals"]["rows_total"] == 1
        assert "amount" not in str(result).lower()

    assert conn.execute("SELECT COUNT(*) FROM budget_transaction_candidates").fetchone()[0] == 0


def test_upload_unknown_csv_returns_understandable_error() -> None:
    conn = db(); setup_base(conn)

    result = preview_uploaded_budget_import(conn, filename="unknown.csv", csv_text="foo;bar\n1;2\n", profile="auto")

    assert result["status"] == "failed"
    assert result["errors"]
    assert "Profil" in result["errors"][0] or "profile" in result["errors"][0].lower()
    assert result["totals"]["error_rows"] >= 1


def test_upload_confirm_creates_candidates_idempotently_and_links_review_filter() -> None:
    conn = db(); _account, expense, income = setup_base(conn)
    preview = preview_uploaded_budget_import(conn, filename="visa.csv", csv_text=VISA_CSV, profile="auto", default_category_id=expense, income_category_id=income)

    first = confirm_uploaded_budget_import_candidates(conn, preview["preview_id"])
    second = confirm_uploaded_budget_import_candidates(conn, preview["preview_id"])
    rows = list_transaction_candidates(conn, import_session_id=first["import_session_id"], status="open")
    session = get_budget_import_session(conn, first["import_session_id"])

    assert first["status"] == "candidates_created"
    assert first["totals"]["new_candidates"] == 1
    assert second["totals"]["new_candidates"] == 0
    assert second["totals"]["already_processed"] >= 1
    assert len(rows) == 1
    assert f"import_session_id={first['import_session_id']}" in first["review_url"]
    assert "status=open" in first["review_url"]
    assert session["source"] == "VISA"
    assert list_budget_import_sessions(conn)[0]["import_session_id"] == second["import_session_id"]


def test_user_candidate_counts_exclude_legacy_and_match_monthly_dashboard() -> None:
    conn = db(); setup_base(conn)
    rows = [
        ("pending", "unclear", 1, "2026-05-01"),
        ("auto_categorized", "subscription_auto", 0, "2026-05-02"),
        ("needs_review", "admin_other", 1, "2026-05-03"),
        ("duplicate_candidate", "duplicate", 1, "2026-05-04"),
        ("transfer_candidate", "transfer_candidate", 1, "2026-05-05"),
        ("confirmed", "unclear", 0, "2026-05-06"),
        ("ignored", "unclear", 1, "2026-05-07"),
        ("superseded", "unclear", 1, "2026-05-08"),
        ("covered_by_source", "covered_by_source", 0, "2026-05-09"),
        ("already_processed", "already_processed", 0, "2026-05-10"),
        ("pending", "legacy", 1, "2025-05-01"),
    ]
    for idx, (status, classification, requires_review, date) in enumerate(rows, start=1):
        conn.execute(
            """
            INSERT INTO budget_transaction_candidates(transaction_candidate_id, source_file_label, source_row_or_range, source_type, transaction_date, description, amount_original, currency_original, confidence, requires_review, status, classification, created_at, updated_at)
            VALUES (?, 'test.csv', ?, 'visa_credit_card', ?, ?, '1.00', 'CHF', '0.5', ?, ?, ?, '2026-05-19T00:00:00', '2026-05-19T00:00:00')
            """,
            (f"cand_{idx}", f"R{idx}", date, f"row {idx}", requires_review, status, classification),
        )
    conn.commit()

    review = review_candidate_summary(conn, budget_year="2026")
    monthly = get_monthly_import_dashboard(conn, budget_year="2026")

    assert review["open_total"] == 4
    assert review["possible_duplicates"] == 1
    assert review["covered_by_source"] == 1
    assert review["already_processed"] == 1
    assert monthly["user_counts"]["open_total"] == review["open_total"]
    assert monthly["user_counts"]["review_needed"] == review["review_needed"]
    assert monthly["user_counts"]["possible_duplicates"] == review["possible_duplicates"]
