"""Phase 7S.1E email queue and retry metadata

Revision ID: 20260610_phase_7s1e_email_queue
Revises: 20260609_phase_7s1c_email_preferences
Create Date: 2026-06-10
"""
from __future__ import annotations

from alembic import op
import sqlalchemy as sa


revision = "20260610_phase_7s1e_email_queue"
down_revision = "20260609_phase_7s1c_email_preferences"
branch_labels = None
depends_on = None


def _existing_columns(table_name: str) -> set[str]:
    bind = op.get_bind()
    inspector = sa.inspect(bind)
    try:
        return {col["name"] for col in inspector.get_columns(table_name)}
    except Exception:
        return set()


def _add_column_if_missing(table_name: str, column: sa.Column) -> None:
    if column.name not in _existing_columns(table_name):
        op.add_column(table_name, column)


def upgrade() -> None:
    _add_column_if_missing("email_logs", sa.Column("attempt_count", sa.Integer(), nullable=False, server_default="0"))
    _add_column_if_missing("email_logs", sa.Column("max_attempts", sa.Integer(), nullable=False, server_default="3"))
    _add_column_if_missing("email_logs", sa.Column("queue_priority", sa.Integer(), nullable=False, server_default="100"))
    _add_column_if_missing("email_logs", sa.Column("is_retryable", sa.Boolean(), nullable=False, server_default=sa.true()))
    _add_column_if_missing("email_logs", sa.Column("queued_at", sa.DateTime(timezone=True), nullable=True))
    _add_column_if_missing("email_logs", sa.Column("next_retry_at", sa.DateTime(timezone=True), nullable=True))
    _add_column_if_missing("email_logs", sa.Column("last_attempt_at", sa.DateTime(timezone=True), nullable=True))
    _add_column_if_missing("email_logs", sa.Column("processing_started_at", sa.DateTime(timezone=True), nullable=True))

    existing_indexes = {idx["name"] for idx in sa.inspect(op.get_bind()).get_indexes("email_logs")}
    for name, cols in {
        "ix_email_logs_queue_priority": ["queue_priority"],
        "ix_email_logs_is_retryable": ["is_retryable"],
        "ix_email_logs_queued_at": ["queued_at"],
        "ix_email_logs_next_retry_at": ["next_retry_at"],
        "ix_email_logs_last_attempt_at": ["last_attempt_at"],
        "ix_email_logs_processing_started_at": ["processing_started_at"],
    }.items():
        if name not in existing_indexes:
            op.create_index(name, "email_logs", cols)


def downgrade() -> None:
    # Safe downgrade for development only. SQLite may not support all drop-column
    # operations depending on version, so production rollback should use backups.
    for name in [
        "ix_email_logs_processing_started_at",
        "ix_email_logs_last_attempt_at",
        "ix_email_logs_next_retry_at",
        "ix_email_logs_queued_at",
        "ix_email_logs_is_retryable",
        "ix_email_logs_queue_priority",
    ]:
        try:
            op.drop_index(name, table_name="email_logs")
        except Exception:
            pass
    for col in [
        "processing_started_at",
        "last_attempt_at",
        "next_retry_at",
        "queued_at",
        "is_retryable",
        "queue_priority",
        "max_attempts",
        "attempt_count",
    ]:
        try:
            op.drop_column("email_logs", col)
        except Exception:
            pass
