#!/usr/bin/env python3
"""Read-only/apply repair for SEND_INVOICE tasks whose invoice already exists.

The script keeps legacy reconciliation tasks aligned with the current document
state.  It does not send emails.  With --apply it updates pending SEND_INVOICE
notes/actions when a current Jasmin invoice is linked to the opportunity.
"""
from __future__ import annotations

import argparse
import json
from typing import Any, Dict

from sqlalchemy import text

from app.db import engine


def _json(value: Any) -> str:
    return json.dumps(value or {}, ensure_ascii=False, default=str)


def _money(value: Any, currency: str = "EUR") -> str:
    if value is None or value == "":
        return ""
    try:
        return f"{float(value):,.2f} {currency or 'EUR'}".replace(",", "X").replace(".", ",").replace("X", ".")
    except Exception:
        return str(value)


def find_candidates(limit: int = 100) -> list[Dict[str, Any]]:
    with engine.begin() as conn:
        rows = conn.execute(text("""
            WITH current_invoice AS (
                SELECT DISTINCT ON (opportunity_id)
                    id::text AS document_id,
                    opportunity_id,
                    document_number,
                    external_id,
                    total_amount,
                    amount,
                    currency,
                    status,
                    system,
                    role,
                    is_primary,
                    created_at
                FROM commercial_documents
                WHERE document_kind = 'invoice'
                  AND opportunity_id IS NOT NULL
                  AND COALESCE(is_primary, TRUE) = TRUE
                  AND COALESCE(role, 'current') IN ('current', 'accepted')
                ORDER BY opportunity_id, created_at DESC, id DESC
            )
            SELECT
                t.id::text AS task_id,
                t.action_code,
                t.route,
                t.action,
                t.note,
                t.status AS task_status,
                t.priority,
                t.opportunity_id::text,
                o.title AS opportunity_title,
                o.customer_name,
                o.stage AS opportunity_stage,
                i.document_id,
                i.document_number,
                i.external_id,
                i.total_amount,
                i.amount,
                i.currency,
                i.status AS invoice_status,
                i.system AS invoice_system
            FROM tasks t
            JOIN opportunities o ON o.id = t.opportunity_id
            JOIN current_invoice i ON i.opportunity_id = t.opportunity_id
            WHERE t.status = 'pending'
              AND t.action_code = 'SEND_INVOICE'
            ORDER BY t.created_at DESC
            LIMIT :limit
        """), {"limit": int(limit)}).mappings().all()
    return [dict(row) for row in rows]


def apply_candidate(row: Dict[str, Any]) -> int:
    number = str(row.get("document_number") or row.get("external_id") or "fatura").strip()
    amount = _money(row.get("total_amount") or row.get("amount"), str(row.get("currency") or "EUR"))
    action = f"Enviar fatura {number} ao cliente"
    note = f"Enviar fatura {number} ao cliente." + (f" Valor: {amount}." if amount else "") + " PDF/anexo disponível para envio automático."
    patch = {
        "invoice_delivery_context": {
            "document_id": row.get("document_id"),
            "document_number": number,
            "amount": str(row.get("total_amount") or row.get("amount") or ""),
            "currency": str(row.get("currency") or "EUR"),
            "pdf_available": True,
            "synced_by": "sync_invoice_delivery_context",
        }
    }
    with engine.begin() as conn:
        result = conn.execute(text("""
            UPDATE tasks
            SET action = CAST(:action AS TEXT),
                note = CAST(:note AS TEXT),
                updated_at = now(),
                metadata = COALESCE(metadata, '{}'::jsonb) || CAST(:metadata_patch AS JSONB)
            WHERE id = CAST(:task_id AS UUID)
              AND status = 'pending'
              AND action_code = 'SEND_INVOICE'
        """), {
            "task_id": row["task_id"],
            "action": action,
            "note": note,
            "metadata_patch": _json(patch),
        })
    return int(getattr(result, "rowcount", 0) or 0)


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--apply", action="store_true", help="Update matching pending SEND_INVOICE task notes/actions")
    parser.add_argument("--limit", type=int, default=100)
    args = parser.parse_args()

    rows = find_candidates(args.limit)
    print(f"SEND_INVOICE pendentes com fatura atual ligada: {len(rows)}")
    updated = 0
    for row in rows:
        print("-", row["task_id"], row.get("customer_name"), row.get("document_number") or row.get("external_id"), row.get("total_amount") or row.get("amount"))
        if args.apply:
            updated += apply_candidate(row)
    if args.apply:
        print(f"updated: {updated}")
    else:
        print("dry-run apenas. Usa --apply para atualizar contexto da task.")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
