"""dashboarddefaults: add fqdn, make ipaddress nullable.

Map a display PC to its role/location by its STABLE FQDN (derived from the BIOS
serial, F<serial>.<domain>) instead of only its DHCP-changeable IP. IP stays as
a nullable fallback. Idempotent.
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '7d31_dashboarddefault_fqdn'
down_revision = '7d30_apitoken_resourcescopes'
branch_labels = None
depends_on = None


def _has_column(bind, table, column):
    inspector = sa.inspect(bind)
    if table not in inspector.get_table_names():
        return False
    return column in {c['name'] for c in inspector.get_columns(table)}


def _col_nullable(bind, table, column):
    inspector = sa.inspect(bind)
    for c in inspector.get_columns(table):
        if c['name'] == column:
            return c.get('nullable', True)
    return True


def _has_index(bind, table, index):
    inspector = sa.inspect(bind)
    if table not in inspector.get_table_names():
        return False
    return index in {i['name'] for i in inspector.get_indexes(table)}


def upgrade():
    bind = op.get_bind()
    if not _has_column(bind, 'dashboarddefaults', 'fqdn'):
        op.add_column('dashboarddefaults',
                      sa.Column('fqdn', sa.String(191), nullable=True))
    if not _has_index(bind, 'dashboarddefaults', 'idx_dashboarddefaults_fqdn'):
        op.create_index('idx_dashboarddefaults_fqdn', 'dashboarddefaults',
                        ['fqdn'], unique=True)
    # IP is now optional (an FQDN-only mapping has no IP).
    if not _col_nullable(bind, 'dashboarddefaults', 'ipaddress'):
        op.alter_column('dashboarddefaults', 'ipaddress',
                        existing_type=sa.String(50), nullable=True)


def downgrade():
    bind = op.get_bind()
    if _has_index(bind, 'dashboarddefaults', 'idx_dashboarddefaults_fqdn'):
        op.drop_index('idx_dashboarddefaults_fqdn',
                      table_name='dashboarddefaults')
    if _has_column(bind, 'dashboarddefaults', 'fqdn'):
        op.drop_column('dashboarddefaults', 'fqdn')
    # ipaddress is left nullable: reverting to NOT NULL could fail on FQDN-only
    # rows that legitimately have no IP.
