from __future__ import annotations

from jarvis_finance.services.budget_accounts import confirm_create_budget_account, create_budget_account_preview
from jarvis_finance.services.budget_categories import confirm_create_category
from jarvis_finance.services.budget_csv_imports import import_budget_csv_text
from jarvis_finance.services.budget_imports import list_transaction_candidates, mark_candidate_type
from jarvis_finance.services.budget_overview import get_budget_overview
from jarvis_finance.services.budget_transactions import confirm_budget_transaction, confirm_transfer, list_budget_transactions, list_budget_transfers
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):
    raiffeisen = confirm_create_budget_account(conn, {"name": "Raiffeisen Marcel", "account_type": "checking", "currency": "CHF"})["entity_id"]
    akb = confirm_create_budget_account(conn, {"name": "AKB Melanie", "account_type": "checking", "currency": "CHF"})["entity_id"]
    visa = confirm_create_budget_account(conn, {"name": "VISA", "account_type": "credit_card", "currency": "CHF"})["entity_id"]
    food = confirm_create_category(conn, {"name": "Essen & Haushalt", "category_type": "expense"})["entity_id"]
    income = confirm_create_category(conn, {"name": "Lohn", "category_type": "income"})["entity_id"]
    return raiffeisen, akb, visa, food, income


def test_transfers_do_not_count_as_income_or_expense_and_are_listed_with_cashflow_accounts() -> None:
    conn = db()
    raiffeisen, akb, _visa, food, income = setup_base(conn)
    confirm_budget_transaction(conn, {"account_id": raiffeisen, "transaction_type": "expense", "transaction_date": "2026-01-05", "description": "Supermarkt", "amount_original": "10.00", "currency_original": "CHF", "category_id": food})
    confirm_budget_transaction(conn, {"account_id": akb, "transaction_type": "income", "transaction_date": "2026-01-06", "description": "Lohn", "amount_original": "20.00", "currency_original": "CHF", "category_id": income})

    transfer = confirm_transfer(conn, {"from_account_id": raiffeisen, "to_account_id": akb, "amount_original": "5.00", "currency_original": "CHF", "transaction_date": "2026-01-07", "description": "Haushaltsübertrag", "transfer_type": "internal_transfer"})

    assert transfer["audit_id"]
    assert len(list_budget_transactions(conn, transaction_type="expense", status="confirmed", year="2026")) == 1
    assert len(list_budget_transactions(conn, transaction_type="income", status="confirmed", year="2026")) == 1
    transfers = list_budget_transfers(conn, year="2026")
    assert transfers[0]["from_account_name"] == "Raiffeisen Marcel"
    assert transfers[0]["to_account_name"] == "AKB Melanie"
    assert transfers[0]["transfer_type"] == "internal_transfer"
    overview = get_budget_overview(conn, month="2026-01")
    assert overview["actual_expense_chf"] == "10.00"
    assert overview["actual_income_chf"] == "20.00"


def test_credit_card_and_true_wealth_transfers_are_not_expenses_and_true_wealth_cash_can_be_previewed() -> None:
    conn = db()
    raiffeisen, _akb, visa, food, _income = setup_base(conn)
    tw_preview = create_budget_account_preview(conn, {"name": "True Wealth Cash", "account_type": "investment_cash", "currency": "CHF", "notes": "Investment-Transfer-Ziel; keine Beträge"})
    true_wealth_cash = confirm_create_budget_account(conn, tw_preview["payload"])["entity_id"]

    confirm_budget_transaction(conn, {"account_id": raiffeisen, "transaction_type": "expense", "transaction_date": "2026-02-01", "description": "Apotheke", "amount_original": "7.00", "currency_original": "CHF", "category_id": food})
    confirm_transfer(conn, {"from_account_id": raiffeisen, "to_account_id": visa, "amount_original": "100.00", "currency_original": "CHF", "transaction_date": "2026-02-02", "description": "VISA Kartenabrechnung", "transfer_type": "credit_card_payment"})
    confirm_transfer(conn, {"from_account_id": raiffeisen, "to_account_id": true_wealth_cash, "amount_original": "200.00", "currency_original": "CHF", "transaction_date": "2026-02-03", "description": "True Wealth Einzahlung", "transfer_type": "investment_transfer"})

    expenses = list_budget_transactions(conn, transaction_type="expense", status="confirmed", year="2026")
    transfers = list_budget_transfers(conn, year="2026")
    assert [tx["description"] for tx in expenses] == ["Apotheke"]
    assert {t["transfer_type"] for t in transfers} == {"credit_card_payment", "investment_transfer"}
    assert any(t["to_account_name"] == "True Wealth Cash" for t in transfers)


def test_transfer_review_marks_true_wealth_target_and_writes_audit_without_productive_booking() -> None:
    conn = db()
    _raiffeisen, _akb, _visa, _food, income = setup_base(conn)
    csv_text = "IBAN;Booked At;Text;Credit/Debit Amount;Balance;Valuta Date\nCH1;2026-03-01;True Wealth Einzahlung;-200.00;0;2026-03-01\nCH1;2026-03-02;AKB Umbuchung eigenes Konto;-50.00;0;2026-03-02\n"
    import_budget_csv_text(conn, "raiffeisen_bank", csv_text, source_file_label="raiffeisen.csv", dry_run=False, income_category_id=income)
    rows = list_transaction_candidates(conn, include_reference=True, sort_by="date", sort_dir="asc")

    true_wealth = rows[0]
    result = mark_candidate_type(conn, true_wealth["transaction_candidate_id"], "investment_transfer", "UAT: True Wealth Cash target")

    assert true_wealth["classification"] == "investment_transfer"
    assert result["classification"] == "investment_transfer"
    assert result["audit_id"]
    assert conn.execute("SELECT COUNT(*) FROM budget_transactions").fetchone()[0] == 0
    assert conn.execute("SELECT COUNT(*) FROM audit_log WHERE entity_id=?", (true_wealth["transaction_candidate_id"],)).fetchone()[0] >= 1
