from __future__ import annotations
from decimal import Decimal, InvalidOperation
from pathlib import Path
from sqlite3 import Connection
from jarvis_finance.crypto.transactions import record_crypto_buy, record_crypto_sell, record_crypto_transfer
from .common import ImportResult, clean, create_import_session, require_text, source_hash
from .dry_run import read_csv_rows
from .row_hash import compute_row_hash
REQUIRED_COLUMNS={"transaction_type","asset_symbol","quantity"}

def dec(v,line,field,default=None):
    t=clean(v)
    if not t and default is not None: return default
    try: return Decimal(t)
    except (InvalidOperation, ValueError) as exc: raise ValueError(f"line {line}: {field} invalid decimal") from exc

def wallet(conn,name,required=True):
    if not name and not required: return None
    r=conn.execute("SELECT wallet_id FROM crypto_wallets WHERE wallet_name=?",(name,)).fetchone()
    if not r: raise ValueError(f"wallet not found: {name}")
    return r['wallet_id']
def asset(conn,symbol,cg=None):
    if cg:
        r=conn.execute("SELECT asset_id FROM crypto_assets WHERE coingecko_id=?",(cg,)).fetchone()
        if r: return r['asset_id']
    rs=conn.execute("SELECT asset_id FROM crypto_assets WHERE symbol=?",(symbol.upper(),)).fetchall()
    if len(rs)!=1: raise ValueError(f"asset not uniquely found: {symbol}")
    return rs[0]['asset_id']
def account(conn,name):
    if not name: return None
    r=conn.execute("SELECT account_id FROM accounts WHERE account_name=?",(name,)).fetchone()
    if not r: raise ValueError(f"account not found: {name}")
    return r['account_id']

def import_crypto_transactions_csv(conn:Connection,path:str|Path,*,commit:bool,source_filename:str|None=None)->ImportResult:
    rows,errors=read_csv_rows(path,REQUIRED_COLUMNS); source_filename=source_filename or Path(path).name
    new=existing=0; vals=[]; seen=set()
    for line,row in enumerate(rows,start=2):
        try:
            rh=compute_row_hash(row)
            if rh in seen: raise ValueError(f"line {line}: duplicate row hash in source file")
            seen.add(rh)
            if conn.execute("SELECT 1 FROM crypto_transactions WHERE tx_hash=?",(clean(row.get('tx_hash')),)).fetchone() and clean(row.get('tx_hash')):
                existing+=1; continue
            tx=require_text(row,'transaction_type',line).lower(); aid=asset(conn,require_text(row,'asset_symbol',line),clean(row.get('coingecko_id')) or None); qty=dec(row.get('quantity'),line,'quantity')
            if qty<=0: raise ValueError(f"line {line}: quantity must be > 0")
            vals.append((tx,aid,qty,row,line)); new+=1
        except ValueError as exc: errors.append(str(exc))
    status='failed' if errors else ('committed' if commit else 'dry_run_ok')
    if commit and not errors:
        for tx,aid,qty,row,line in vals:
            note=clean(row.get('notes')) or 'synthetic crypto transaction import'; feeq=dec(row.get('fee_quantity'),line,'fee_quantity',Decimal('0')); feeo=dec(row.get('fee_original'),line,'fee_original',Decimal('0')); fx=dec(row.get('fx_rate_to_chf'),line,'fx_rate_to_chf',None) if clean(row.get('fx_rate_to_chf')) else None
            if tx=='transfer': record_crypto_transfer(conn,asset_id=aid,from_wallet_id=wallet(conn,require_text(row,'from_wallet_name',line)),to_wallet_id=wallet(conn,require_text(row,'to_wallet_name',line)),quantity=qty,fee_quantity=feeq,tx_hash=clean(row.get('tx_hash')) or None,note=note)
            elif tx=='buy': record_crypto_buy(conn,account_id=account(conn,require_text(row,'account_name',line)),asset_id=aid,to_wallet_id=wallet(conn,require_text(row,'to_wallet_name',line)),quantity=qty,gross_amount_original=dec(row.get('gross_amount_original'),line,'gross_amount_original'),fee_original=feeo,fee_currency=clean(row.get('fee_currency')) or None,currency=require_text(row,'currency_original',line),fx_rate_to_chf=fx,note=note)
            elif tx=='sell': record_crypto_sell(conn,account_id=account(conn,require_text(row,'account_name',line)),asset_id=aid,from_wallet_id=wallet(conn,require_text(row,'from_wallet_name',line)),quantity=qty,gross_amount_original=dec(row.get('gross_amount_original'),line,'gross_amount_original'),fee_original=feeo,fee_currency=clean(row.get('fee_currency')) or None,currency=require_text(row,'currency_original',line),fx_rate_to_chf=fx,note=note)
            elif tx=='fee': record_crypto_transfer(conn,asset_id=aid,from_wallet_id=wallet(conn,require_text(row,'from_wallet_name',line)),to_wallet_id=wallet(conn,require_text(row,'to_wallet_name',line)),quantity=Decimal('0.00000001'),fee_quantity=qty,note=note)
            else: raise ValueError(f"line {line}: unsupported crypto transaction type")
    sid=create_import_session(conn,import_type='crypto_transactions',source_filename=source_filename,file_hash=source_hash(path),status=status,rows_total=len(rows),rows_imported=new if commit and not errors else 0,rows_failed=len(errors),errors=errors,notes='dry run' if not commit else None)
    return ImportResult(sid,'crypto_transactions',status,len(rows),new if not errors else 0,existing,len(errors),errors)
