"""Timbrado de CFDI: ``fin.invoice_stamps`` y ``fin.invoices.stamping_mode``.

Escrita a mano y no con ``--autogenerate``: el autogenerate de este proyecto arrastra
drift preexistente entre los modelos y la base (llaves foráneas de ``core``, cambios de
tipo en ``invite_tokens``), y generaba 1,516 operaciones ajenas a este ticket. Aquí van
sólo los dos cambios del timbrado.

Revision ID: h3i4j5k6l7m8
Revises: f7a8b9c0d1e2
Create Date: 2026-08-07 00:00:00.000000

"""
from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op

revision: str = "h3i4j5k6l7m8"
down_revision: Union[str, None] = "f7a8b9c0d1e2"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    # ---------- fin.invoices: modo de timbrado por factura ----------
    # NOT NULL con server_default: las facturas existentes quedan en 'pruebas', que es el
    # valor seguro. Marcar como 'produccion' es siempre una decisión explícita.
    op.add_column(
        "invoices",
        sa.Column(
            "stamping_mode",
            sa.String(length=12),
            nullable=False,
            server_default=sa.text("'pruebas'"),
        ),
        schema="fin",
    )

    # ---------- fin.invoice_stamps ----------
    op.create_table(
        "invoice_stamps",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("tenant_id", sa.Integer(), nullable=False),
        sa.Column("company_id", sa.Integer(), nullable=False),
        sa.Column("invoice_id", sa.Integer(), nullable=False),
        sa.Column("mode", sa.String(length=12), nullable=False),
        sa.Column("status", sa.String(length=12), nullable=False, server_default=sa.text("'pendiente'")),
        # Timbre Fiscal Digital
        sa.Column("uuid", sa.String(length=36), nullable=True),
        sa.Column("stamped_at", sa.DateTime(), nullable=True),
        sa.Column("pac_rfc", sa.String(length=13), nullable=True),
        sa.Column("sat_cert_number", sa.String(length=20), nullable=True),
        sa.Column("sat_seal", sa.Text(), nullable=True),
        sa.Column("cfd_seal", sa.Text(), nullable=True),
        # Respuesta del PAC
        sa.Column("pac_code", sa.Integer(), nullable=True),
        sa.Column("pac_balance", sa.Integer(), nullable=True),
        sa.Column("error_message", sa.Text(), nullable=True),
        sa.Column("xml_file_key", sa.String(length=512), nullable=True),
        sa.Column("created_by", sa.String(length=64), nullable=True),
        sa.Column("created_at", sa.DateTime(), nullable=False, server_default=sa.text("now()")),
        sa.Column("updated_at", sa.DateTime(), nullable=False, server_default=sa.text("now()")),
        sa.Column("deleted_at", sa.DateTime(), nullable=True),
        sa.ForeignKeyConstraint(["invoice_id"], ["fin.invoices.id"]),
        sa.PrimaryKeyConstraint("id"),
        schema="fin",
    )
    op.create_index("ix_fin_invoice_stamps_id", "invoice_stamps", ["id"], schema="fin")
    op.create_index("ix_fin_invoice_stamps_invoice_id", "invoice_stamps", ["invoice_id"], schema="fin")
    op.create_index("ix_fin_invoice_stamps_status", "invoice_stamps", ["status"], schema="fin")
    op.create_index("ix_fin_invoice_stamps_uuid", "invoice_stamps", ["uuid"], schema="fin")
    # Un UUID lo emite el SAT una sola vez. Parcial sobre uuid IS NOT NULL porque los intentos
    # fallidos no traen UUID y colisionarían entre sí bajo un único convencional.
    op.create_index(
        "uq_fin_invoice_stamps_uuid",
        "invoice_stamps",
        ["uuid"],
        unique=True,
        schema="fin",
        postgresql_where=sa.text("uuid IS NOT NULL AND deleted_at IS NULL"),
    )


def downgrade() -> None:
    op.drop_index("uq_fin_invoice_stamps_uuid", table_name="invoice_stamps", schema="fin")
    op.drop_index("ix_fin_invoice_stamps_uuid", table_name="invoice_stamps", schema="fin")
    op.drop_index("ix_fin_invoice_stamps_status", table_name="invoice_stamps", schema="fin")
    op.drop_index("ix_fin_invoice_stamps_invoice_id", table_name="invoice_stamps", schema="fin")
    op.drop_index("ix_fin_invoice_stamps_id", table_name="invoice_stamps", schema="fin")
    op.drop_table("invoice_stamps", schema="fin")
    op.drop_column("invoices", "stamping_mode", schema="fin")
