"""Support teams get contacts; drop the legacy appowners pair

Restructures the application support model: supportteams keeps teamname (now
unique) + teamurl (widened to TEXT for ServiceNow group deep links), gains a
child supportteamcontacts table, and sheds its single-owner appownerid FK and
the appowners table. Each legacy team's appowner is migrated into ONE contact.
applications.supportteamid is unchanged (it already points at supportteams).

Idempotent guards throughout so it is safe on a partially-migrated box.

Revision ID: 7d18_supportteamcontacts
Revises: 7d17_machines_rename
Create Date: 2026-07-11

"""
from alembic import op
import sqlalchemy as sa


revision = '7d18_supportteamcontacts'
down_revision = '7d17_machines_rename'
branch_labels = None
depends_on = None


def _has_table(insp, name):
    return insp.has_table(name)


def _has_column(insp, table, column):
    return column in [c['name'] for c in insp.get_columns(table)]


def _has_unique(insp, table, name):
    return name in [u['name'] for u in insp.get_unique_constraints(table)]


def upgrade():
    bind = op.get_bind()
    insp = sa.inspect(bind)

    # 1. New contacts table.
    if not _has_table(insp, 'supportteamcontacts'):
        op.create_table(
            'supportteamcontacts',
            sa.Column('contactid', sa.Integer(), primary_key=True),
            sa.Column('supportteamid', sa.Integer(), nullable=False),
            sa.Column('name', sa.String(length=100), nullable=False),
            sa.Column('sso', sa.String(length=50), nullable=True),
            sa.Column('sortorder', sa.Integer(), nullable=False,
                      server_default='0'),
            sa.Column('createddate', sa.DateTime(), nullable=False),
            sa.Column('modifieddate', sa.DateTime(), nullable=False),
            sa.Column('isactive', sa.Boolean(), nullable=False,
                      server_default='1'),
            sa.ForeignKeyConstraint(
                ['supportteamid'], ['supportteams.supportteamid'],
                ondelete='CASCADE'),
        )

    # 2. Migrate each team's appowner into one contact.
    if _has_table(insp, 'appowners') and \
            _has_column(insp, 'supportteams', 'appownerid'):
        bind.exec_driver_sql(
            "INSERT INTO supportteamcontacts "
            "(supportteamid, name, sso, sortorder, isactive, "
            " createddate, modifieddate) "
            "SELECT st.supportteamid, ao.appowner, ao.sso, 0, 1, "
            " NOW(), NOW() "
            "FROM supportteams st "
            "JOIN appowners ao ON st.appownerid = ao.appownerid "
            "WHERE st.appownerid IS NOT NULL")

    # 3. teamname becomes unique.
    if not _has_unique(insp, 'supportteams', 'uq_supportteams_teamname'):
        op.create_unique_constraint(
            'uq_supportteams_teamname', 'supportteams', ['teamname'])

    # 4. Widen teamurl to TEXT.
    op.alter_column('supportteams', 'teamurl',
                    existing_type=sa.String(length=255),
                    type_=sa.Text(), existing_nullable=True)

    # 5. Drop the appownerid FK + column, then the appowners table.
    if _has_column(insp, 'supportteams', 'appownerid'):
        for fk in insp.get_foreign_keys('supportteams'):
            if 'appownerid' in fk['constrained_columns'] and fk.get('name'):
                bind.exec_driver_sql(
                    f"ALTER TABLE supportteams DROP FOREIGN KEY {fk['name']}")
        op.drop_column('supportteams', 'appownerid')
    bind.exec_driver_sql("DROP TABLE IF EXISTS appowners")


def downgrade():
    bind = op.get_bind()
    insp = sa.inspect(bind)

    # Recreate appowners.
    if not _has_table(insp, 'appowners'):
        op.create_table(
            'appowners',
            sa.Column('appownerid', sa.Integer(), primary_key=True),
            sa.Column('appowner', sa.String(length=100), nullable=False),
            sa.Column('sso', sa.String(length=50), nullable=True),
            sa.Column('email', sa.String(length=100), nullable=True),
            sa.Column('createddate', sa.DateTime(), nullable=False),
            sa.Column('modifieddate', sa.DateTime(), nullable=False),
            sa.Column('isactive', sa.Boolean(), nullable=False,
                      server_default='1'),
        )

    # Re-add the appownerid FK column.
    if not _has_column(insp, 'supportteams', 'appownerid'):
        op.add_column('supportteams',
                      sa.Column('appownerid', sa.Integer(), nullable=True))
        op.create_foreign_key(
            'fk_supportteams_appownerid', 'supportteams', 'appowners',
            ['appownerid'], ['appownerid'])

    # Best-effort data reversal: each team's first active contact -> an owner.
    if _has_table(insp, 'supportteamcontacts'):
        rows = bind.execute(sa.text(
            "SELECT supportteamid, name, sso FROM supportteamcontacts "
            "WHERE isactive = 1 ORDER BY supportteamid, sortorder, contactid"))
        seen = set()
        for row in rows:
            if row.supportteamid in seen:
                continue
            seen.add(row.supportteamid)
            result = bind.execute(sa.text(
                "INSERT INTO appowners "
                "(appowner, sso, isactive, createddate, modifieddate) "
                "VALUES (:name, :sso, 1, NOW(), NOW())"),
                {'name': row.name, 'sso': row.sso})
            bind.execute(sa.text(
                "UPDATE supportteams SET appownerid = :ownerid "
                "WHERE supportteamid = :teamid"),
                {'ownerid': result.lastrowid, 'teamid': row.supportteamid})

    # Narrow teamurl back to VARCHAR(255).
    op.alter_column('supportteams', 'teamurl',
                    existing_type=sa.Text(),
                    type_=sa.String(length=255), existing_nullable=True)

    # Drop the unique constraint.
    if _has_unique(insp, 'supportteams', 'uq_supportteams_teamname'):
        op.drop_constraint('uq_supportteams_teamname', 'supportteams',
                           type_='unique')

    op.drop_table('supportteamcontacts')
