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.reports_v1 import generate_report_v1, list_reports_v1, preview_report_v1
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 seed(conn):
    account = confirm_create_budget_account(conn, {"name": "Haushalt", "account_type": "cash", "currency": "CHF"})["entity_id"]
    expense_cat = confirm_create_category(conn, {"name": "Haushalt", "category_type": "expense", "monthly_budget": "100.00"})["entity_id"]
    income_cat = confirm_create_category(conn, {"name": "Lohn", "category_type": "income"})["entity_id"]
    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
    ('income_ok', ?, ?, '2026-05-01', 'income', 'Lohn', '100.00', 'CHF', '100.00', 'not_needed', 'confirmed', 'manual', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    ('expense_ok', ?, ?, '2026-05-02', 'expense', 'Haushalt Laden', '-30.00', 'CHF', '-30.00', 'not_needed', 'confirmed', 'manual', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    ('candidate_no_count', ?, ?, '2026-05-03', 'expense', 'Pending', '-999.00', 'CHF', '-999.00', 'not_needed', 'draft', 'manual', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    ('transfer_no_count', ?, ?, '2026-05-04', 'transfer', 'Transfer', '-500.00', 'CHF', '-500.00', 'not_needed', 'confirmed', 'manual', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
    """, (account, income_cat, account, expense_cat, account, expense_cat, account, expense_cat))
    conn.execute("""INSERT INTO budget_transaction_candidates (transaction_candidate_id, source_type, source_file_label, transaction_date, description, amount_original, currency_original, status, classification, requires_review, created_at, updated_at)
    VALUES
    ('cand_review', 'visa_credit_card', 'visa.csv', '2026-05-05', 'Review', '-10.00', 'CHF', 'needs_review', 'expense_candidate', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    ('cand_dup', 'migros_purchase', 'migros.csv', '2026-05-06', 'Dup', '-11.00', 'CHF', 'duplicate_candidate', 'expense_candidate', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
    ('cand_covered', 'migros_purchase', 'migros.csv', '2026-05-07', 'Covered', '-12.00', 'CHF', 'covered_by_source', 'expense_candidate', 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
    """)
    conn.commit()


def test_reports_v1_generate_all_types_runtime_only_metadata_and_audit(tmp_path: Path) -> None:
    conn = db(); seed(conn)
    repo = Path.cwd()
    reports_dir = tmp_path / "runtime_reports"
    report_types = ["budget_monthly", "cashflow_household", "budget_review_status", "crypto_status", "portfolio_status"]

    for kind in report_types:
        result = generate_report_v1(conn, report_type=kind, period="2026-05", format="html", reports_dir=reports_dir, repo_root=repo)
        path = Path(result["path"])
        assert result["runtime_only"] is True
        assert result["metadata"]["report_type"] == kind
        assert path.exists()
        assert reports_dir in path.parents
        assert repo not in path.parents
        assert path.suffix == ".html"
        assert "Datenqualität" in path.read_text(encoding="utf-8")

    listed = list_reports_v1(reports_dir=reports_dir)
    assert len(listed) >= len(report_types)
    audit = reports_dir / "report_events.jsonl"
    assert audit.exists()
    assert audit.read_text(encoding="utf-8").count("report_generated") >= len(report_types)


def test_budget_monthly_report_counts_confirmed_only_and_candidates_separately(tmp_path: Path) -> None:
    conn = db(); seed(conn)
    preview = preview_report_v1(conn, report_type="budget_monthly", period="2026-05")

    assert preview["totals"]["income_chf"] == "100.00"
    assert preview["totals"]["expense_chf"] == "30.00"
    assert preview["totals"]["net_cashflow_chf"] == "70.00"
    assert preview["review"]["open_total"] >= 1
    assert preview["review"]["possible_duplicates"] >= 1
    assert preview["review"]["covered_by_source"] >= 1
    assert preview["sections"]["top_categories"]
    assert "999.00" not in str(preview)
    assert "500.00" not in str(preview)


def test_cashflow_and_review_reports_expose_required_sections() -> None:
    conn = db(); seed(conn)
    cashflow = preview_report_v1(conn, report_type="cashflow_household", period="2026")
    review = preview_report_v1(conn, report_type="budget_review_status", period="2026-05")

    assert cashflow["sections"]["monthly_cashflow"]
    assert "transfers_separate" in cashflow["sections"]
    assert "savings_rate_percent" in cashflow["totals"]
    assert "fixed_cost_ratio_percent" in cashflow["totals"]
    assert review["sections"]["candidates_by_source"]
    assert review["review"]["possible_duplicates"] >= 1
    assert review["review"]["covered_by_source"] >= 1
