from __future__ import annotations

from pathlib import Path

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_monthly_import import preview_drive_monthly_import
from jarvis_finance.services.budget_recurring import confirm_manual_recurring_payment
from jarvis_finance.services.finance_command_center import build_finance_command_center, generate_monthly_report
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_budget(conn):
    account = confirm_create_budget_account(conn, {"name": "Haushalt", "account_type": "cash", "currency": "CHF"})["entity_id"]
    food = 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"]
    media = confirm_create_category(conn, {"name": "Elektronische Medien", "category_type": "expense"})["entity_id"]
    return account, food, income, media


def seed_confirmed_transactions(conn, account, food, income):
    conn.execute(
        """INSERT INTO budget_transactions (
            budget_transaction_id, account_id, category_id, transaction_date, transaction_type,
            description, amount_original, currency_original, amount_chf, fx_status, status, source_type, created_at, updated_at
        ) VALUES
        ('tx_income', ?, ?, '2026-05-25', 'income', 'Lohn', '100.00', 'CHF', '100.00', 'not_needed', 'confirmed', 'manual', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
        ('tx_expense', ?, ?, '2026-05-10', 'expense', 'Haushalt', '-30.00', 'CHF', '-30.00', 'not_needed', 'confirmed', 'manual', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
        ('tx_candidate_should_not_count', ?, ?, '2026-05-11', 'expense', 'Candidate-like pending', '-999.00', 'CHF', '-999.00', 'not_needed', 'draft', 'manual', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
        ('tx_transfer_should_not_count', ?, ?, '2026-05-12', 'transfer', 'Interner Transfer', '-500.00', 'CHF', '-500.00', 'not_needed', 'confirmed', 'manual', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
        """,
        (account, income, account, food, account, food, account, food),
    )
    conn.commit()


def test_command_center_kpis_monthly_close_imports_todos_and_compact_sections() -> None:
    conn = db(); account, food, income, media = setup_budget(conn); seed_confirmed_transactions(conn, account, food, income)
    preview_drive_monthly_import(conn, [{"id": "visa", "name": "VISA_Mai.csv", "text": "TransactionId,CardId,Date,Amount,Currency,MerchantName,Details\nT1,C1,2026-05-01,-10.00,CHF,Netflix,Abo\n"}], dry_run=False, default_category_id=media, income_category_id=income)
    confirm_manual_recurring_payment(conn, {"name": "Netflix", "category_id": media, "expected_amount_text": "10.00", "currency": "CHF", "frequency": "monthly", "recurring_type": "subscription"})

    center = build_finance_command_center(conn, month="2026-05")

    assert center["purpose"] == "finance_command_center_v1"
    assert center["kpis"]["income_month_chf"] == "100.00"
    assert center["kpis"]["expense_month_chf"] == "30.00"
    assert center["kpis"]["net_cashflow_month_chf"] == "70.00"
    assert center["kpis"]["savings_rate_percent"] == "70.00"
    assert center["kpis"]["open_review_candidates"] >= 1
    assert set(center["monthly_close"]["checklist"]) >= {"akb_csv_imported", "visa_csv_imported", "backup_created"}
    assert any(item["source"] == "VISA" for item in center["import_status"])
    assert "top_overruns" in center["budget_status_compact"]
    assert center["fixed_costs_compact"]["active_subscriptions"] >= 1
    assert "asset_allocation" in center["portfolio_crypto_compact"]
    assert any(todo["priority"] in {"high", "medium", "low"} and todo["link"] for todo in center["todos"])


def test_command_center_counts_only_confirmed_actuals_and_excludes_transfers_candidates() -> None:
    conn = db(); account, food, income, _media = setup_budget(conn); seed_confirmed_transactions(conn, account, food, income)

    center = build_finance_command_center(conn, month="2026-05")

    assert center["kpis"]["income_month_chf"] == "100.00"
    assert center["kpis"]["expense_month_chf"] == "30.00"
    assert center["kpis"]["net_cashflow_month_chf"] == "70.00"


def test_monthly_report_is_runtime_only_markdown_and_not_in_repo(tmp_path: Path) -> None:
    conn = db(); account, food, income, _media = setup_budget(conn); seed_confirmed_transactions(conn, account, food, income)
    repo_root = Path.cwd()
    runtime_reports_dir = tmp_path / "runtime_reports"

    report = generate_monthly_report(conn, month="2026-05", reports_dir=runtime_reports_dir, repo_root=repo_root)

    report_path = Path(report["path"])
    assert report["format"] == "markdown"
    assert report_path.exists()
    assert runtime_reports_dir in report_path.parents
    assert repo_root not in report_path.parents
    text = report_path.read_text()
    assert "# Monatsreport 2026-05" in text
    assert "Disclaimer" in text
    assert "Preview → Confirm → Audit" in text


def test_month_boundaries_use_exclusive_next_month_and_invalid_month_is_rejected(tmp_path: Path) -> None:
    conn = db(); account, food, income, _media = setup_budget(conn); seed_confirmed_transactions(conn, account, food, income)
    conn.execute(
        """INSERT INTO budget_transactions (budget_transaction_id, account_id, category_id, transaction_date, transaction_type, description, amount_original, currency_original, amount_chf, fx_status, status, source_type, created_at, updated_at)
        VALUES ('tx_june_must_not_count', ?, ?, '2026-06-01', 'expense', 'June', '-70.00', 'CHF', '-70.00', 'not_needed', 'confirmed', 'manual', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)""",
        (account, food),
    )
    conn.commit()

    center = build_finance_command_center(conn, month="2026-05")
    assert center["kpis"]["expense_month_chf"] == "30.00"
    try:
        generate_monthly_report(conn, month="2026-05/../../evil", reports_dir=tmp_path / "runtime_reports", repo_root=Path.cwd())
    except ValueError as exc:
        assert "month_must_be_yyyy_mm" in str(exc)
    else:
        raise AssertionError("invalid month accepted")
