from __future__ import annotations

from decimal import Decimal
from pathlib import Path

from jarvis_finance.crypto.assets import create_crypto_asset
from jarvis_finance.crypto.holdings import calculate_crypto_holdings, create_initial_holding_snapshot
from jarvis_finance.crypto.wallets import create_wallet
from jarvis_finance.imports.cash_balances_importer import import_cash_balances_csv
from jarvis_finance.imports.crypto_holdings_importer import import_crypto_holdings_csv
from jarvis_finance.imports.crypto_transactions_importer import import_crypto_transactions_csv
from jarvis_finance.imports.crypto_wallets_importer import import_crypto_wallets_csv
from jarvis_finance.imports.watchlist_importer import import_watchlist_csv
from jarvis_finance.storage.database import connect_memory
from jarvis_finance.storage.migrations import apply_migrations


def setup_conn():
    c=connect_memory(); apply_migrations(c)
    c.execute("INSERT INTO platforms(platform_id,name,platform_type,default_currency,created_at) VALUES('p1','Synthetic Broker','Bank/Broker','CHF','now')")
    c.execute("INSERT INTO accounts(account_id,platform_id,account_name,account_type,currency,created_at) VALUES('a1','p1','Synthetic Cash','cash','CHF','now')")
    c.commit(); return c

def write_csv(tmp_path: Path, name: str, text: str) -> Path:
    p = tmp_path / name; p.write_text(text, encoding='utf-8'); return p


def test_crypto_wallet_and_holding_import_dry_run_commit_existing_and_precision(tmp_path: Path) -> None:
    c=setup_conn()
    wallets=write_csv(tmp_path,'wallets.csv','wallet_name,wallet_type,notes\nSynthetic Cold,Hardware Wallet,synthetic\n')
    assert import_crypto_wallets_csv(c,wallets,commit=False).status == 'dry_run_ok'
    res=import_crypto_wallets_csv(c,wallets,commit=True); assert res.rows_new == 1
    assert import_crypto_wallets_csv(c,wallets,commit=True).rows_existing == 1
    holdings=write_csv(tmp_path,'holdings.csv','wallet_name,coin_name,symbol,coingecko_id,quantity,verification_status,last_verified_at,legacy_snapshot_value_chf\nSynthetic Cold,Synthetic Bitcoin,BTC,bitcoin,0.00000001,verified,2026-01-01T00:00:00Z,999.99\n')
    res=import_crypto_holdings_csv(c,holdings,commit=True); assert res.rows_new == 1
    h=calculate_crypto_holdings(c)
    aid=c.execute("SELECT asset_id FROM crypto_assets WHERE symbol='BTC'").fetchone()['asset_id']
    wid=c.execute("SELECT wallet_id FROM crypto_wallets WHERE wallet_name='Synthetic Cold'").fetchone()['wallet_id']
    assert h.wallet_holdings[(wid,aid)].quantity == Decimal('0.00000001')
    row=c.execute('SELECT quantity, typeof(quantity), legacy_snapshot_value_chf, typeof(legacy_snapshot_value_chf) FROM crypto_holdings').fetchone()
    assert row['quantity'] == '0.00000001' and row['typeof(quantity)'] == 'text'
    assert row['legacy_snapshot_value_chf'] == '999.99' and row['typeof(legacy_snapshot_value_chf)'] == 'text'


def test_crypto_transactions_import_transfer_and_buy_create_audit_and_no_float_rounding(tmp_path: Path) -> None:
    c=setup_conn(); w1=create_wallet(c,wallet_name='Synthetic A',wallet_type='Hardware Wallet'); w2=create_wallet(c,wallet_name='Synthetic B',wallet_type='Software Wallet'); aid=create_crypto_asset(c,coin_name='Synthetic Bitcoin',symbol='BTC',coingecko_id='bitcoin')
    create_initial_holding_snapshot(c,asset_id=aid,wallet_id=w1,quantity=Decimal('0.00000003'),verification_status='verified',note='synthetic')
    csv=write_csv(tmp_path,'crypto_tx.csv','transaction_type,asset_symbol,quantity,from_wallet_name,to_wallet_name,account_name,gross_amount_original,currency_original,fee_quantity,fee_original,fee_currency,fx_rate_to_chf,notes\ntransfer,BTC,0.00000001,Synthetic A,Synthetic B,,,,0.00000001,,,,synthetic transfer\nbuy,BTC,0.00000002,,Synthetic B,Synthetic Cash,10,CHF,,0.50,CHF,1,synthetic buy\n')
    res=import_crypto_transactions_csv(c,csv,commit=True)
    assert res.status == 'committed'
    h=calculate_crypto_holdings(c)
    assert h.wallet_holdings[(w1,aid)].quantity == Decimal('0.00000001')
    assert h.wallet_holdings[(w2,aid)].quantity == Decimal('0.00000003')
    assert c.execute("SELECT COUNT(*) AS c FROM transactions WHERE source_type='crypto'").fetchone()['c'] == 2
    assert c.execute("SELECT COUNT(*) AS c FROM audit_log WHERE action IN ('crypto_transfer','crypto_buy')").fetchone()['c'] == 2


def test_watchlist_and_cash_balance_importers(tmp_path: Path) -> None:
    c=setup_conn()
    watch=write_csv(tmp_path,'watch.csv','name,asset_class,reason,status,target_entry_price,target_entry_currency,investment_case,bear_case\nSynthetic Idea,Crypto,synthetic reason,active,123.45,CHF,case,bear\n')
    assert import_watchlist_csv(c,watch,commit=True).rows_new == 1
    assert c.execute('SELECT reason FROM watchlist WHERE name=?',('Synthetic Idea',)).fetchone()['reason'] == 'synthetic reason'
    cash=write_csv(tmp_path,'cash.csv','account_name,balance_date,currency,amount_original,fx_rate_to_chf,notes\nSynthetic Cash,2026-01-01,CHF,1000,1,synthetic cash snapshot\n')
    assert import_cash_balances_csv(c,cash,commit=True).rows_new == 1
    row=c.execute("SELECT transaction_type, net_amount_original FROM transactions WHERE transaction_type='initial_cash_snapshot'").fetchone()
    assert row['transaction_type'] == 'initial_cash_snapshot'
    assert Decimal(row['net_amount_original']) == Decimal('1000')
