from __future__ import annotations

from sqlite3 import Connection, IntegrityError

from jarvis_finance.audit.log import record_audit_event
from jarvis_finance.imports.common import stable_id, utc_now

VALID_WALLET_TYPES = {
    "Hardware Wallet",
    "Software Wallet",
    "Exchange",
    "Bank/Broker",
    "DeFi",
    "Sonstiges",
}


def _validate_wallet_type(wallet_type: str) -> None:
    if wallet_type not in VALID_WALLET_TYPES:
        raise ValueError(f"wallet_type must be one of {sorted(VALID_WALLET_TYPES)}")


def create_wallet(
    conn: Connection,
    *,
    wallet_name: str,
    wallet_type: str,
    wallet_address: str | None = None,
    platform_provider: str | None = None,
    network_chain: str | None = None,
    owner: str | None = None,
    last_verified_at: str | None = None,
    notes: str | None = None,
) -> str:
    _validate_wallet_type(wallet_type)
    now = utc_now()
    wallet_id = stable_id("wallet", wallet_name)
    try:
        conn.execute(
            """
            INSERT INTO crypto_wallets(
                wallet_id, wallet_name, wallet_type, platform_provider, network_chain,
                wallet_address, owner, is_active, last_verified_at, notes, created_at
            ) VALUES (?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?)
            """,
            (wallet_id, wallet_name, wallet_type, platform_provider, network_chain, wallet_address, owner, last_verified_at, notes, now),
        )
    except IntegrityError as exc:
        raise ValueError("wallet_name must be unique") from exc
    record_audit_event(
        conn,
        source="crypto_wallets",
        action="create_wallet",
        entity_type="crypto_wallet",
        entity_id=wallet_id,
        new_values={"wallet_name": wallet_name, "wallet_type": wallet_type},
        confirmed=True,
        created_by="system",
    )
    conn.commit()
    return wallet_id


def get_wallet(conn: Connection, wallet_id: str):
    row = conn.execute("SELECT * FROM crypto_wallets WHERE wallet_id=?", (wallet_id,)).fetchone()
    if row is None:
        raise KeyError(wallet_id)
    return row


def update_wallet(conn: Connection, wallet_id: str, **changes) -> None:
    allowed = {"wallet_name", "wallet_type", "wallet_address", "platform_provider", "network_chain", "owner", "last_verified_at", "notes", "is_active"}
    if "wallet_type" in changes:
        _validate_wallet_type(changes["wallet_type"])
    clean = {k: v for k, v in changes.items() if k in allowed}
    if not clean:
        return
    clean["updated_at"] = utc_now()
    assignments = ", ".join(f"{k}=?" for k in clean)
    try:
        conn.execute(f"UPDATE crypto_wallets SET {assignments} WHERE wallet_id=?", (*clean.values(), wallet_id))
    except IntegrityError as exc:
        raise ValueError("wallet_name must be unique") from exc
    record_audit_event(
        conn,
        source="crypto_wallets",
        action="update_wallet",
        entity_type="crypto_wallet",
        entity_id=wallet_id,
        new_values=clean,
        confirmed=True,
        created_by="system",
    )
    conn.commit()


def deactivate_wallet(conn: Connection, wallet_id: str, *, note: str) -> None:
    if not note.strip():
        raise ValueError("deactivate wallet requires a note")
    update_wallet(conn, wallet_id, is_active=0, notes=note)
