from __future__ import annotations

import pytest

from jarvis_finance.services.budget_accounts import confirm_create_budget_account
from jarvis_finance.services.budget_categories import (
    confirm_category_merge,
    confirm_create_category,
    delete_empty_category,
    preview_category_merges,
)
from jarvis_finance.services.budget_imports import (
    batch_confirm_safe_candidates,
    bulk_update_transaction_candidate_category,
    ignore_transaction_candidate,
    list_transaction_candidates,
    preview_safe_auto_candidates,
    reopen_transaction_candidate,
    seed_transaction_candidates_from_rows,
)
from jarvis_finance.services.budget_plans import confirm_budget_plan_item
from jarvis_finance.services.budget_transactions import confirm_budget_transaction, list_budget_transactions, update_budget_transaction
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 test_phase17_import_review_bulk_category_ignore_reopen_and_safe_preview() -> None:
    conn = db()
    account = confirm_create_budget_account(conn, {"name": "Budget Konto", "account_type": "cash", "currency": "CHF"})["entity_id"]
    cat = confirm_create_category(conn, {"name": "Abos", "category_type": "expense"})["entity_id"]
    seed_transaction_candidates_from_rows(
        conn,
        [{"Datum": "2026-01-02", "Artikel": "Streaming Abo", "Umsatz": "12.00"}],
        source_file_label="visa.csv",
        source_type="credit_card_csv",
    )
    cid = list_transaction_candidates(conn)[0]["transaction_candidate_id"]
    conn.execute("UPDATE budget_transaction_candidates SET classification='subscription_auto', requires_review=0, status='pending' WHERE transaction_candidate_id=?", (cid,))
    conn.commit()

    result = bulk_update_transaction_candidate_category(conn, candidate_ids=[cid], category_id=cat, note="test bulk")
    assert result == {"updated_count": 1, "skipped_count": 0}
    updated = list_transaction_candidates(conn)[0]
    assert updated["proposed_category_id"] == cat
    assert updated["amount_original"] == "12.00"

    ignored = ignore_transaction_candidate(conn, cid, "test ignore")
    assert ignored["status"] == "ignored"
    reopened = reopen_transaction_candidate(conn, cid, "undo")
    assert reopened["status"] in {"pending", "needs_review"}

    preview = preview_safe_auto_candidates(conn)
    assert preview["count"] == 1
    confirmed = batch_confirm_safe_candidates(conn, account_id=account, candidate_ids=[cid])
    assert confirmed["confirmed_count"] == 1
    assert list_budget_transactions(conn, transaction_type="expense", status="confirmed")


def test_phase17_effective_expenses_filters_and_no_amount_mutation() -> None:
    conn = db()
    account = confirm_create_budget_account(conn, {"name": "Budget Konto", "account_type": "cash", "currency": "CHF"})["entity_id"]
    cat = confirm_create_category(conn, {"name": "Haushalt", "category_type": "expense"})["entity_id"]
    tx = confirm_budget_transaction(conn, {"account_id": account, "transaction_type": "expense", "transaction_date": "2026-02-03", "description": "Merchant X", "amount_original": "42.00", "currency_original": "CHF"})["entity_id"]
    assert list_budget_transactions(conn, transaction_type="expense", status="confirmed", category_id="__uncategorized")
    update_budget_transaction(conn, tx, {"category_id": cat, "tag_names": ["Review"], "change_note": "phase17"})
    assert list_budget_transactions(conn, transaction_type="expense", category_id=cat, tag="Review", search="Merchant")
    with pytest.raises(Exception):
        update_budget_transaction(conn, tx, {"amount_original": "99.00"})


def test_phase17_category_tree_delete_empty_archive_non_empty_and_merge() -> None:
    conn = db()
    account = confirm_create_budget_account(conn, {"name": "Budget Konto", "account_type": "cash", "currency": "CHF"})["entity_id"]
    empty = confirm_create_category(conn, {"name": "Leer", "category_type": "expense"})["entity_id"]
    assert delete_empty_category(conn, empty)["status"] == "deleted"

    target = confirm_create_category(conn, {"name": "Versicherungen", "category_type": "expense"})["entity_id"]
    parent = confirm_create_category(conn, {"name": "Legacy Parent", "category_type": "expense"})["entity_id"]
    source = confirm_create_category(conn, {"name": "versicherungen", "category_type": "expense", "parent_category_id": parent})["entity_id"]
    confirm_budget_transaction(conn, {"account_id": account, "transaction_type": "expense", "transaction_date": "2026-01-10", "description": "Police", "amount_original": "10.00", "currency_original": "CHF", "category_id": source})
    confirm_budget_plan_item(conn, {"plan_month": "2026-01", "category_id": source, "name": "Plan", "monthly_amount_chf": "10.00", "cadence": "monthly", "source_type": "manual"})
    preview = preview_category_merges(conn)
    assert any(target in s["target_category_id"] or source in s["source_category_ids"] for s in preview["suggestions"])
    result = confirm_category_merge(conn, {"target_category_id": target, "source_category_ids": [source], "note": "test merge"})
    assert result["moved_transactions"] == 1
    assert result["moved_budget_plans"] == 1
    assert list_budget_transactions(conn, category_id=target)
    assert conn.execute("SELECT is_active FROM budget_categories WHERE category_id=?", (source,)).fetchone()[0] == 0
