"""printers: printerobservedqueues table (what a bay reported it HAS).

ShopDB already knows what a bay SHOULD have (usesprinter/defaultprinter rows on
the machine). This table holds the other half: the queues a PC reported through
POST /api/collector/printers. Observed and assigned stay in separate tables on
purpose, so observed drift can never be mistaken for desired state.

One row per observed queue; the latest report for a host replaces all of that
host's rows. The unique index on (hostname, queuename) is the guard that turns a
half-finished replace into an IntegrityError instead of duplicate queues.

Explicit ops rather than create_plugin_tables: the helper builds a per-plugin
MetaData filtered to the plugin's own tables, so the foreign key to the core
assets table cannot resolve at CreateTable-compile time. Same reason the backups
baseline spells its ops out.

Guarded both ways, so a re-run (or a database where db.create_all already built
the table) is a no-op.

Revision ID: printers0005observedqueues
Revises: printers0004drivervendor
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'printers0005observedqueues'
down_revision = 'printers0004drivervendor'
branch_labels = None
depends_on = None


def upgrade():
    bind = op.get_bind()
    inspector = sa.inspect(bind)
    if 'printerobservedqueues' in inspector.get_table_names():
        return
    op.create_table(
        'printerobservedqueues',
        sa.Column('printerobservedqueueid', sa.Integer(), nullable=False),
        # Nullable and no index of its own beyond the explicit one below: an
        # unenrolled bay still gets to report, and hostname is what identifies
        # the report.
        sa.Column('assetid', sa.Integer(), nullable=True),
        sa.Column('hostname', sa.String(length=255), nullable=False),
        sa.Column('queuename', sa.String(length=255), nullable=False),
        sa.Column('drivername', sa.String(length=255), nullable=True),
        sa.Column('portname', sa.String(length=255), nullable=True),
        sa.Column('portaddress', sa.String(length=255), nullable=True),
        sa.Column('isdefault', sa.Boolean(), nullable=False,
                  server_default=sa.false()),
        sa.Column('isshared', sa.Boolean(), nullable=False,
                  server_default=sa.false()),
        sa.Column('observedat', sa.DateTime(), nullable=False),
        sa.Column('createddate', sa.DateTime(), nullable=False),
        sa.Column('modifieddate', sa.DateTime(), nullable=False),
        sa.Column('isactive', sa.Boolean(), nullable=False,
                  server_default=sa.true()),
        sa.ForeignKeyConstraint(['assetid'], ['assets.assetid'],
                                ondelete='CASCADE'),
        sa.PrimaryKeyConstraint('printerobservedqueueid'),
        # Doubles as the read index for the hostname filter (leftmost column),
        # so no separate hostname index is created.
        sa.UniqueConstraint('hostname', 'queuename',
                            name='uq_printerobservedqueue_host_queue'),
    )
    # Port address is the primary match key from an observed queue back to a
    # printer asset, so every comparison read hits it.
    op.create_index('idx_printerobservedqueues_portaddress',
                    'printerobservedqueues', ['portaddress'])
    op.create_index('idx_printerobservedqueues_assetid',
                    'printerobservedqueues', ['assetid'])


def downgrade():
    bind = op.get_bind()
    inspector = sa.inspect(bind)
    if 'printerobservedqueues' not in inspector.get_table_names():
        return
    op.drop_index('idx_printerobservedqueues_assetid',
                  table_name='printerobservedqueues')
    op.drop_index('idx_printerobservedqueues_portaddress',
                  table_name='printerobservedqueues')
    op.drop_table('printerobservedqueues')
