from __future__ import annotations

from fastapi import APIRouter, HTTPException, Query
from pydantic import EmailStr

from app.services.bank_workflow import BankWorkflowError
from app.services.ledger_auth import require_firm
from app.services.snelstart import integration_enabled, list_connections
from app.services.snelstart.bank import import_bank_transactions_all
from app.store import (
    BankActorRequest,
    CreateBankTxRequest,
    IgnoreBankTxRequest,
    MatchBankTxRequest,
    store,
)

router = APIRouter(prefix="/v1/bank-transactions", tags=["bank"])


def _workflow_http(exc: BankWorkflowError) -> HTTPException:
    return HTTPException(status_code=400, detail=str(exc))


@router.get("")
def list_bank_transactions(
    platform: str = Query(pattern="^(firm)$"),
    email: EmailStr = Query(...),
    clientId: str | None = None,
    status: str | None = None,
    dateFrom: str | None = None,
    dateTo: str | None = None,
    q: str | None = None,
):
    require_firm(platform=platform, email=str(email))
    connections = list_connections()
    connected_clients = sum(1 for c in connections if c.isConnected)
    return {
        "items": store.list_bank_transactions(
            client_id=clientId,
            status=status,
            date_from=dateFrom,
            date_to=dateTo,
            query=q,
        ),
        "stats": store.bank_transaction_stats(client_id=clientId),
        "snelstart": {
            "integrationEnabled": integration_enabled(),
            "anyConnected": connected_clients > 0,
            "connectedClients": connected_clients,
        },
    }


@router.post("/sync")
def sync_bank_transactions(payload: BankActorRequest):
    require_firm(platform=payload.platform, email=payload.email, actor=payload.actor)
    result = import_bank_transactions_all()
    stats = store.bank_transaction_stats()
    return {
        "imported": result.imported,
        "clientsChecked": result.clientsChecked,
        "connected": result.connectedClients > 0,
        "connectedClients": result.connectedClients,
        "integrationEnabled": result.integrationEnabled,
        "message": result.message,
        "stats": stats,
    }


@router.post("")
def create_bank_transaction(payload: CreateBankTxRequest):
    """Create one real bank row (manual entry / integration testing). Firm-only."""
    require_firm(platform=payload.platform, email=payload.email, actor=payload.actor)
    try:
        return store.create_bank_transaction_manual(payload)
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Client not found") from exc


@router.get("/{tx_id}")
def get_bank_transaction(
    tx_id: str,
    platform: str = Query(pattern="^(firm)$"),
    email: EmailStr = Query(...),
):
    require_firm(platform=platform, email=str(email))
    try:
        return store._find_transaction(tx_id)  # noqa: SLF001
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Bank transaction not found") from exc


@router.get("/{tx_id}/matches")
def get_transaction_matches(
    tx_id: str,
    platform: str = Query(pattern="^(firm)$"),
    email: EmailStr = Query(...),
):
    require_firm(platform=platform, email=str(email))
    try:
        tx = store._find_transaction(tx_id)  # noqa: SLF001
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Bank transaction not found") from exc
    return {"transaction": tx, "matches": store.get_transaction_matches(tx_id)}


@router.get("/{tx_id}/search-matches")
def search_transaction_matches(
    tx_id: str,
    platform: str = Query(pattern="^(firm)$"),
    email: EmailStr = Query(...),
    q: str = Query(min_length=1),
):
    require_firm(platform=platform, email=str(email))
    try:
        store._find_transaction(tx_id)  # noqa: SLF001
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Bank transaction not found") from exc
    return {"items": store.search_transaction_matches(tx_id, q)}


@router.post("/{tx_id}/match")
def approve_bank_match(tx_id: str, payload: MatchBankTxRequest):
    actor = require_firm(platform=payload.platform, email=payload.email, actor=payload.actor)
    try:
        return store.approve_bank_match(
            tx_id,
            invoice_id=payload.invoiceId,
            actor=actor,
            amount=payload.amount,
        )
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Bank transaction or invoice not found") from exc
    except BankWorkflowError as exc:
        raise _workflow_http(exc) from exc


@router.post("/{tx_id}/reject-match")
def reject_bank_match(tx_id: str, payload: BankActorRequest):
    actor = require_firm(platform=payload.platform, email=payload.email, actor=payload.actor)
    try:
        return store.reject_bank_match(tx_id, actor=actor)
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Bank transaction not found") from exc


@router.post("/{tx_id}/ignore")
def ignore_bank_transaction(tx_id: str, payload: IgnoreBankTxRequest):
    actor = require_firm(platform=payload.platform, email=payload.email, actor=payload.actor)
    try:
        return store.ignore_bank_transaction(tx_id, actor=actor, reason=payload.reason)
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Bank transaction not found") from exc
    except BankWorkflowError as exc:
        raise _workflow_http(exc) from exc
