"""Server-side flow listing and export from confirmed source rows.

Lists and exports only cashier-confirmed worksheets. Match state is derived
from current transfer decisions when a source row is claimed; otherwise the
row is labelled 未归集. Company users only see their own company.
"""

from __future__ import annotations

from decimal import Decimal, InvalidOperation
import sqlite3


def _dec(value: object) -> Decimal:
    try:
        return Decimal(str(value or "0"))
    except (InvalidOperation, TypeError):
        return Decimal("0")


def _direction(income: object, expense: object) -> tuple[str, Decimal]:
    income_d = _dec(income)
    expense_d = _dec(expense)
    if expense_d > 0 and income_d <= 0:
        return "付", expense_d
    return "收", income_d if income_d > 0 else expense_d


def _status_label(classification: str | None, pairing: str | None, locked: int | None) -> tuple[str, str]:
    if classification in ("unresolved", "needs_review"):
        return "单边", "danger"
    if classification == "intercompany" and pairing == "paired":
        return "已归集", "success"
    if classification == "intercompany" and locked:
        return "已归集", "success"
    if classification == "intercompany":
        return "待确认", "warn"
    if classification == "same_company":
        return "同公司调拨", "muted"
    if classification == "external":
        return "未归集 · 外部", "muted"
    if classification:
        return "未归集", "muted"
    return "未归集", "muted"


def list_flows(
    connection: sqlite3.Connection,
    *,
    company_id: int | None = None,
    bank: str | None = None,
    account: str | None = None,
    start: str | None = None,
    end: str | None = None,
    keyword: str | None = None,
    limit: int = 200,
    offset: int = 0,
) -> dict[str, object]:
    clauses = ["rv.review_status = 'confirmed'"]
    params: list[object] = []
    if company_id is not None:
        clauses.append("b.company_id = ?")
        params.append(int(company_id))
    if start:
        clauses.append("date(r.transaction_at) >= date(?)")
        params.append(start)
    if end:
        clauses.append("date(r.transaction_at) <= date(?)")
        params.append(end)
    if account:
        clauses.append("r.own_account LIKE ?")
        params.append(f"%{account}%")
    if bank:
        clauses.append("(COALESCE(ba.bank_name, '') LIKE ? OR r.own_name LIKE ?)")
        params.extend([f"%{bank}%", f"%{bank}%"])
    if keyword:
        like = f"%{keyword}%"
        clauses.append(
            "(r.counterparty_name LIKE ? OR r.summary LIKE ? OR r.reference LIKE ? "
            "OR r.purpose LIKE ? OR c.name LIKE ?)"
        )
        params.extend([like, like, like, like, like])
    where = " AND ".join(clauses)
    limit = max(1, min(int(limit), 500))
    offset = max(0, int(offset))
    count_row = connection.execute(
        f"""
        SELECT COUNT(*) AS n
        FROM source_rows r
        JOIN sheet_batches s ON s.id = r.sheet_batch_id
        JOIN import_batches b ON b.id = s.import_batch_id
        JOIN sheet_reviews rv ON rv.sheet_batch_id = s.id
        JOIN companies c ON c.id = b.company_id
        LEFT JOIN bank_accounts ba ON ba.account_number = r.own_account
        WHERE {where}
        """,
        params,
    ).fetchone()
    rows = connection.execute(
        f"""
        SELECT r.id, r.transaction_at, r.income, r.expense, r.balance,
               r.own_account, r.own_name, r.counterparty_account, r.counterparty_name,
               r.counterparty_bank, r.summary, r.purpose, r.reference, r.currency,
               b.id AS batch_id, b.company_id, c.name AS company_name,
               COALESCE(ba.bank_name, '') AS bank_name,
               s.sheet_name, r.source_row,
               d.classification, d.pairing, d.locked, d.effective_at
        FROM source_rows r
        JOIN sheet_batches s ON s.id = r.sheet_batch_id
        JOIN import_batches b ON b.id = s.import_batch_id
        JOIN sheet_reviews rv ON rv.sheet_batch_id = s.id
        JOIN companies c ON c.id = b.company_id
        LEFT JOIN bank_accounts ba ON ba.account_number = r.own_account
        LEFT JOIN transfer_observation_claims toc ON toc.source_row_id = r.id
        LEFT JOIN transfer_match_decisions d ON d.id = toc.decision_id
        WHERE {where}
        ORDER BY r.transaction_at DESC, r.id DESC
        LIMIT ? OFFSET ?
        """,
        [*params, limit, offset],
    ).fetchall()
    items = []
    inflow = Decimal("0")
    outflow = Decimal("0")
    for row in rows:
        direction, amount = _direction(row["income"], row["expense"])
        if direction == "收":
            inflow += amount
        else:
            outflow += amount
        status, status_kind = _status_label(
            row["classification"], row["pairing"], row["locked"]
        )
        tail = str(row["own_account"] or "")[-4:]
        items.append(
            {
                "id": int(row["id"]),
                "date": str(row["transaction_at"] or "")[:10],
                "time": str(row["transaction_at"] or ""),
                "company_id": int(row["company_id"]),
                "company": row["company_name"],
                "bank": row["bank_name"] or "",
                "account": row["own_account"],
                "account_label": (
                    f"{row['bank_name']} · 尾号 {tail}" if row["bank_name"] and tail else (row["own_account"] or "—")
                ),
                "own_name": row["own_name"],
                "direction": direction,
                "peer": row["counterparty_name"] or "—",
                "peer_account": row["counterparty_account"] or "—",
                "peer_bank": row["counterparty_bank"] or "—",
                "summary": row["summary"] or row["purpose"] or "—",
                "serial": row["reference"] or "—",
                "status": status,
                "status_kind": status_kind,
                "amount": str(amount),
                "balance": str(row["balance"] or ""),
                "currency": row["currency"] or "CNY",
                "batch_id": int(row["batch_id"]),
                "batch": f"IMP-{int(row['batch_id']):06d}",
                "locator": f"{row['sheet_name']}!R{row['source_row']}",
                "year_month": str(row["transaction_at"] or "")[:7],
            }
        )
    return {
        "items": items,
        "total": int(count_row["n"]),
        "inflow": str(inflow),
        "outflow": str(outflow),
        "limit": limit,
        "offset": offset,
    }
