from __future__ import annotations

import argparse
from typing import Any

from sqlalchemy import text

from app.db import engine
from app.opportunity_action_task_materializer import ensure_pending_task_for_next_action
from app.opportunity_next_action_service import get_opportunity_next_action


def _candidate_opportunities(limit: int) -> list[dict[str, Any]]:
    sql = text("""
        SELECT DISTINCT o.id::text, o.title, o.customer_name, max(d.created_at) AS last_doc_at
        FROM opportunities o
        JOIN commercial_documents d ON d.opportunity_id = o.id
        WHERE COALESCE(o.status, 'open') = 'open'
          AND d.system = 'jasmin'
          AND d.document_kind = 'invoice'
          AND COALESCE(d.is_active, TRUE) = TRUE
          AND COALESCE(d.role, 'current') IN ('current', 'accepted')
          AND NOT EXISTS (
              SELECT 1
              FROM tasks t
              WHERE t.opportunity_id = o.id
                AND t.status = 'pending'
                AND t.action_code = 'SEND_INVOICE'
          )
        GROUP BY o.id, o.title, o.customer_name
        ORDER BY max(d.created_at) DESC NULLS LAST
        LIMIT :limit
    """)
    with engine.begin() as conn:
        return [dict(r) for r in conn.execute(sql, {"limit": limit}).mappings().all()]


def main() -> None:
    parser = argparse.ArgumentParser(description="Cria tasks SEND_INVOICE em oportunidades cuja próxima ação central é enviar fatura.")
    parser.add_argument("--apply", action="store_true", help="grava alterações; sem isto apenas mostra dry-run")
    parser.add_argument("--limit", type=int, default=200)
    args = parser.parse_args()

    candidates = _candidate_opportunities(args.limit)
    print(f"apply={args.apply} candidates={len(candidates)}")

    to_create: list[tuple[dict[str, Any], dict[str, Any]]] = []
    skipped = 0
    errors = 0
    for opp in candidates:
        try:
            decision = get_opportunity_next_action(opp["id"])
            code = str(decision.get("action_code") or decision.get("next_action", {}).get("code") or "").upper()
            if code == "SEND_INVOICE":
                to_create.append((opp, decision))
            else:
                skipped += 1
        except Exception as exc:
            errors += 1
            print(f"ERROR opp={opp.get('id')} title={opp.get('title')} error={exc}")

    print(f"SEND_INVOICE_TO_CREATE={len(to_create)} skipped={skipped} errors={errors}")
    for opp, decision in to_create:
        doc = decision.get("document_number") or decision.get("next_action", {}).get("document_number") or ""
        print(f"- opp={opp['id']} doc={doc} title={opp.get('title')} customer={opp.get('customer_name')}")
        if args.apply:
            result = ensure_pending_task_for_next_action(
                opp["id"],
                decision,
                source="repair_missing_send_invoice_tasks",
                actor="repair-script",
            )
            print(f"  result={result}")

    print("SUMMARY")
    print(f"created_or_existing={len(to_create) if args.apply else 0}")
    print(f"dry_run={not args.apply}")


if __name__ == "__main__":
    main()
