from __future__ import annotations

from pathlib import Path

from jarvis_finance.imports.accounts_importer import import_accounts_csv
from jarvis_finance.imports.instruments_importer import import_instruments_csv
from jarvis_finance.imports.transactions_importer import import_transactions_csv
from jarvis_finance.storage.database import connect_memory
from jarvis_finance.storage.migrations import apply_migrations


def seed_reference_data(conn, tmp_path: Path) -> None:
    accounts = tmp_path / "accounts.csv"
    accounts.write_text(
        "platform_name,platform_type,account_name,account_type,currency,performance_included,is_health_reserve,notes\n"
        "Demo Broker,broker,Demo Depot,brokerage,CHF,1,0,Synthetic only\n",
        encoding="utf-8",
    )
    instruments = tmp_path / "instruments.csv"
    instruments.write_text(
        "asset_class,name,ticker,isin,exchange,currency,country,sector,data_provider_primary,notes\n"
        "equity,Demo Global AG,DGA,CH0000000001,SIX,CHF,CH,Technology,dummy,Synthetic only\n",
        encoding="utf-8",
    )
    import_accounts_csv(conn, accounts, commit=True, source_filename="accounts.csv")
    import_instruments_csv(conn, instruments, commit=True, source_filename="instruments.csv")


def test_transactions_import_validates_and_writes_with_audit(tmp_path: Path) -> None:
    conn = connect_memory()
    apply_migrations(conn)
    seed_reference_data(conn, tmp_path)
    path = tmp_path / "transactions.csv"
    path.write_text(
        "transaction_type,platform_name,account_name,trade_date,settlement_date,name,ticker,isin,quantity,price_original,gross_amount_original,fee_original,tax_original,net_amount_original,currency_original,fx_rate_to_chf,fx_source,external_transaction_id,notes\n"
        "buy,Demo Broker,Demo Depot,2026-01-15,2026-01-17,Demo Global AG,DGA,CH0000000001,10,100,1000,5,0,1005,CHF,1,not_needed,demo-txn-001,Synthetic buy\n",
        encoding="utf-8",
    )

    result = import_transactions_csv(conn, path, commit=True, source_filename="transactions.csv")

    assert result.rows_new == 1
    txn = conn.execute("SELECT transaction_type, quantity, is_confirmed FROM transactions").fetchone()
    assert txn["transaction_type"] == "buy"
    assert float(txn["quantity"]) == 10
    assert txn["is_confirmed"] == 1
    assert conn.execute("SELECT COUNT(*) AS n FROM audit_log WHERE entity_type='transaction'").fetchone()["n"] == 1


def test_transactions_import_rejects_buy_with_non_positive_quantity(tmp_path: Path) -> None:
    conn = connect_memory()
    apply_migrations(conn)
    seed_reference_data(conn, tmp_path)
    path = tmp_path / "bad_transactions.csv"
    path.write_text(
        "transaction_type,platform_name,account_name,trade_date,name,ticker,isin,quantity,price_original,gross_amount_original,fee_original,tax_original,net_amount_original,currency_original,fx_rate_to_chf,fx_source,external_transaction_id,notes\n"
        "buy,Demo Broker,Demo Depot,2026-01-15,Demo Global AG,DGA,CH0000000001,0,100,1000,5,0,1005,CHF,1,not_needed,demo-txn-002,Synthetic bad buy\n",
        encoding="utf-8",
    )

    result = import_transactions_csv(conn, path, commit=True, source_filename="bad_transactions.csv")

    assert result.rows_failed == 1
    assert "quantity" in result.errors[0]
    assert conn.execute("SELECT COUNT(*) AS n FROM transactions").fetchone()["n"] == 0


def test_transactions_import_marks_missing_fx_for_foreign_currency(tmp_path: Path) -> None:
    conn = connect_memory()
    apply_migrations(conn)
    seed_reference_data(conn, tmp_path)
    path = tmp_path / "transactions.csv"
    path.write_text(
        "transaction_type,platform_name,account_name,trade_date,name,ticker,isin,quantity,price_original,gross_amount_original,fee_original,tax_original,net_amount_original,currency_original,fx_rate_to_chf,fx_source,external_transaction_id,notes\n"
        "buy,Demo Broker,Demo Depot,2026-01-15,Demo Global AG,DGA,CH0000000001,1,100,100,0,0,100,USD,,manual_missing,demo-txn-003,Synthetic missing fx\n",
        encoding="utf-8",
    )

    result = import_transactions_csv(conn, path, commit=True, source_filename="transactions.csv")

    assert result.rows_new == 1
    txn = conn.execute("SELECT currency_original, fx_status, quality_status FROM transactions").fetchone()
    assert txn["currency_original"] == "USD"
    assert txn["fx_status"] == "missing"
    assert txn["quality_status"] == "incomplete"
    assert conn.execute("SELECT COUNT(*) AS n FROM alerts WHERE priority='kritisch'").fetchone()["n"] == 1


def test_transactions_import_is_idempotent_by_external_id_and_row_hash(tmp_path: Path) -> None:
    conn = connect_memory()
    apply_migrations(conn)
    seed_reference_data(conn, tmp_path)
    path = tmp_path / "transactions.csv"
    path.write_text(
        "transaction_type,platform_name,account_name,trade_date,name,ticker,isin,quantity,price_original,gross_amount_original,fee_original,tax_original,net_amount_original,currency_original,fx_rate_to_chf,fx_source,external_transaction_id,notes\n"
        "initial_position_snapshot,Demo Broker,Demo Depot,2026-01-15,Demo Global AG,DGA,CH0000000001,10,,,,,,CHF,1,not_needed,demo-snap-001,Synthetic initial position\n",
        encoding="utf-8",
    )

    first = import_transactions_csv(conn, path, commit=True, source_filename="transactions.csv")
    second = import_transactions_csv(conn, path, commit=True, source_filename="transactions.csv")

    assert first.rows_new == 1
    assert second.rows_existing == 1
    assert conn.execute("SELECT COUNT(*) AS n FROM transactions").fetchone()["n"] == 1
    row = conn.execute("SELECT transaction_type, notes FROM transactions").fetchone()
    assert row["transaction_type"] == "initial_position_snapshot"
    assert "Initial snapshot" in row["notes"]
