#!/usr/bin/env python3
"""Identify or close opportunities that were probably created from system messages.

Conservative by default: use --dry-run to list candidates. Use --apply to mark
safe candidates as LOST with a metadata reason. It only targets opportunities
with value 0, no commercial documents and no shipments.
"""
from __future__ import annotations

import argparse
import json
import uuid

from sqlalchemy import text

from app.db import engine
from app.opportunity_service import ensure_opportunity_schema

SYSTEM_TERMS = (
    "mail delivery subsystem",
    "mailer-daemon",
    "postmaster",
    "returned mail",
    "undelivered mail",
    "delivery status notification",
    "failure notice",
    "mail delivery failed",
)


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


def find_candidates(limit: int = 100) -> list[dict]:
    ensure_opportunity_schema()
    like_sql = " OR ".join(
        ["lower(coalesce(o.title,'') || ' ' || coalesce(o.customer_name,'') || ' ' || coalesce(o.customer_email,'') || ' ' || coalesce(o.metadata::text,'')) LIKE :term_{}".format(i) for i, _ in enumerate(SYSTEM_TERMS)]
    )
    params = {f"term_{i}": f"%{term}%" for i, term in enumerate(SYSTEM_TERMS)}
    params["limit"] = int(limit)
    sql = text(f"""
        SELECT o.id::text, o.title, o.customer_name, o.customer_email, o.value_amount, o.stage, o.status, o.created_at
        FROM opportunities o
        WHERE o.status = 'open'
          AND COALESCE(o.value_amount, 0) = 0
          AND NOT EXISTS (SELECT 1 FROM commercial_documents cd WHERE cd.opportunity_id = o.id)
          AND NOT EXISTS (SELECT 1 FROM shipments s WHERE s.opportunity_id = o.id)
          AND ({like_sql})
        ORDER BY o.created_at DESC
        LIMIT :limit
    """)
    with engine.begin() as conn:
        rows = conn.execute(sql, params).mappings().all()
    return [dict(row) for row in rows]


def close_candidates(candidates: list[dict]) -> int:
    if not candidates:
        return 0
    ids = [row["id"] for row in candidates]
    with engine.begin() as conn:
        for opportunity_id in ids:
            conn.execute(text("""
                UPDATE opportunities
                SET status = 'closed',
                    stage = 'LOST',
                    closed_at = COALESCE(closed_at, now()),
                    updated_at = now(),
                    metadata = COALESCE(metadata, '{}'::jsonb) || CAST(:metadata AS JSONB)
                WHERE id = CAST(:opportunity_id AS UUID)
            """), {
                "opportunity_id": opportunity_id,
                "metadata": _json({"closed_reason": "system_or_bounce_created_by_mistake", "closed_by": "cleanup_non_commercial_opportunities"}),
            })
            conn.execute(text("""
                INSERT INTO opportunity_events (id, opportunity_id, event_type, from_stage, to_stage, note, payload, created_by)
                VALUES (CAST(:id AS UUID), CAST(:opportunity_id AS UUID), 'cleanup_closed_non_commercial', NULL, 'LOST', :note, CAST(:payload AS JSONB), 'system')
            """), {
                "id": str(uuid.uuid4()),
                "opportunity_id": opportunity_id,
                "note": "Oportunidade fechada por parecer mensagem automática/bounce sem atividade comercial.",
                "payload": _json({"reason": "system_or_bounce_created_by_mistake"}),
            })
    return len(ids)


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--limit", type=int, default=100)
    parser.add_argument("--apply", action="store_true", help="Apply changes. Without this, only prints candidates.")
    args = parser.parse_args()
    candidates = find_candidates(limit=args.limit)
    print(f"Found {len(candidates)} candidate(s).")
    for row in candidates:
        print(f"- {row.get('id')} | {row.get('title')} | {row.get('customer_name')} | {row.get('created_at')}")
    if args.apply:
        total = close_candidates(candidates)
        print(f"Closed {total} candidate(s).")
    else:
        print("Dry-run only. Re-run with --apply to close candidates.")


if __name__ == "__main__":
    main()
