#!/usr/bin/env python3
"""Repair premature shipment tasks created from Odoo picking state assigned.

Dry-run by default. The script only touches pending CREATE_SHIPMENT tasks when:
- the opportunity has an Odoo physical_status link with an outgoing picking assigned;
- no physical_validation=validated link exists;
- the picking is not done.
"""
from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

from sqlalchemy import text

PROJECT_ROOT = Path(__file__).resolve().parent.parent
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

from app.db import engine


def _rows(limit: int) -> list[dict]:
    with engine.begin() as conn:
        rows = conn.execute(text("""
            SELECT
                t.id::text AS task_id,
                o.id::text AS opportunity_id,
                o.customer_name,
                o.stage,
                t.action_code,
                t.metadata AS task_metadata,
                ps.payload AS physical_payload,
                COALESCE(pv.status, '') AS validation_status
            FROM tasks t
            JOIN opportunities o ON o.id = t.opportunity_id
            JOIN operation_links ps
              ON ps.opportunity_id = o.id
             AND ps.system = 'odoo'
             AND ps.external_type = 'physical_status'
            LEFT JOIN operation_links pv
              ON pv.opportunity_id = o.id
             AND pv.system = 'odoo'
             AND pv.external_type = 'physical_validation'
            WHERE t.status = 'pending'
              AND t.action_code = 'CREATE_SHIPMENT'
              AND COALESCE(pv.status, '') <> 'validated'
              AND EXISTS (
                  SELECT 1
                  FROM jsonb_array_elements(
                      COALESCE(ps.payload->'outgoing_pickings', ps.payload->'pickings', '[]'::jsonb)
                  ) p
                  WHERE COALESCE(p->>'state', '') = 'assigned'
              )
              AND NOT EXISTS (
                  SELECT 1
                  FROM jsonb_array_elements(
                      COALESCE(ps.payload->'outgoing_pickings', ps.payload->'pickings', '[]'::jsonb)
                  ) p
                  WHERE COALESCE(p->>'state', '') = 'done'
              )
            ORDER BY t.created_at
            LIMIT :limit
        """), {"limit": limit}).mappings().all()
    return [dict(r) for r in rows]


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument('--apply', action='store_true')
    parser.add_argument('--limit', type=int, default=100)
    args = parser.parse_args()

    rows = _rows(args.limit)
    print(f"Premature CREATE_SHIPMENT tasks: {len(rows)}")
    for row in rows:
        print(f"{row['stage']:18} | {row['customer_name']}")
    if not args.apply:
        print('Dry-run only. Use --apply after reviewing the tasks.')
        return 0

    if not rows:
        return 0

    with engine.begin() as conn:
        for row in rows:
            metadata = dict(row.get('task_metadata') or {})
            metadata.update({
                'corrected_by': 'migration_v4928_1_5_130',
                'previous_action_code': 'CREATE_SHIPMENT',
                'correction_reason': 'Odoo assigned means stock reserved; physical validation still required',
            })
            conn.execute(text("""
                UPDATE tasks
                SET action_code = 'VALIDATE_PHYSICAL_ORDER',
                    route = 'logistica',
                    action = 'Validar encomenda física',
                    note = 'O picking está reservado no Odoo. Confirmar produtos, quantidades, embalagem e preparação física antes de criar o envio.',
                    safe_to_post = FALSE,
                    metadata = CAST(:metadata AS JSONB),
                    updated_at = now()
                WHERE id = CAST(:task_id AS UUID)
                  AND status = 'pending'
                  AND action_code = 'CREATE_SHIPMENT'
            """), {'task_id': row['task_id'], 'metadata': json.dumps(metadata, ensure_ascii=False)})
            conn.execute(text("""
                UPDATE opportunities
                SET stage = CASE WHEN stage = 'READY_TO_SHIP' THEN 'ORDER_PREPARATION' ELSE stage END,
                    last_action_code = 'VALIDATE_PHYSICAL_ORDER',
                    updated_at = now(),
                    metadata = COALESCE(metadata, '{}'::jsonb) || jsonb_build_object(
                        'assigned_picking_requires_physical_validation', TRUE,
                        'assigned_picking_gate_version', 'v4928.1.5.130'
                    )
                WHERE id = CAST(:opportunity_id AS UUID)
            """), {'opportunity_id': row['opportunity_id']})
    print(f"Tasks converted: {len(rows)}")
    return 0


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