"""v0.16.0 migration

Revision ID: 2af2c0629b37
Revises: 3c4d5e6f7a8b
Create Date: 2025-10-05 22:47:48.949687

"""

from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = "2af2c0629b37"
down_revision: Union[str, None] = "3c4d5e6f7a8b"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_index(
        op.f("ix_sign_up_tokens_user_id"), "sign_up_tokens", ["user_id"], unique=False
    )

    # Delete all existing sessions before altering the refresh_token column
    op.execute("DELETE FROM users_sessions")
    # Alter the refresh_token column to be shorter and to reflect that it is hashed
    op.alter_column(
        "users_sessions",
        "refresh_token",
        existing_type=sa.VARCHAR(length=500),
        type_=sa.String(length=255),
        comment="Session hashed refresh token",
        existing_comment="Session refresh token",
        existing_nullable=False,
    )

    # Create table identity_providers
    op.create_table(
        "identity_providers",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column(
            "name",
            sa.String(length=100),
            nullable=False,
            comment="Display name of the IdP",
        ),
        sa.Column(
            "slug", sa.String(length=50), nullable=False, comment="URL-safe identifier"
        ),
        sa.Column(
            "provider_type",
            sa.String(length=50),
            nullable=False,
            comment="Type: oidc, oauth2, saml",
        ),
        sa.Column(
            "enabled",
            sa.Boolean(),
            nullable=False,
            comment="Whether this provider is enabled",
        ),
        sa.Column(
            "client_id",
            sa.String(length=512),
            nullable=True,
            comment="OAuth2/OIDC client ID (encrypted)",
        ),
        sa.Column(
            "client_secret",
            sa.String(length=512),
            nullable=True,
            comment="OAuth2/OIDC client secret (encrypted)",
        ),
        sa.Column(
            "issuer_url",
            sa.String(length=500),
            nullable=True,
            comment="OIDC issuer/discovery URL",
        ),
        sa.Column(
            "authorization_endpoint",
            sa.String(length=500),
            nullable=True,
            comment="OAuth2/OIDC authorization endpoint",
        ),
        sa.Column(
            "token_endpoint",
            sa.String(length=500),
            nullable=True,
            comment="OAuth2/OIDC token endpoint",
        ),
        sa.Column(
            "userinfo_endpoint",
            sa.String(length=500),
            nullable=True,
            comment="OIDC userinfo endpoint",
        ),
        sa.Column(
            "jwks_uri",
            sa.String(length=500),
            nullable=True,
            comment="OIDC JWKS URI for token verification",
        ),
        sa.Column(
            "scopes",
            sa.String(length=500),
            nullable=True,
            comment="OAuth2/OIDC scopes to request",
        ),
        sa.Column(
            "icon",
            sa.String(length=100),
            nullable=True,
            comment="Icon name (FontAwesome) or custom URL",
        ),
        sa.Column(
            "auto_create_users",
            sa.Boolean(),
            nullable=False,
            comment="Automatically create users on first login",
        ),
        sa.Column(
            "sync_user_info",
            sa.Boolean(),
            nullable=False,
            comment="Sync user info on each login",
        ),
        sa.Column(
            "user_mapping",
            sa.JSON(),
            nullable=True,
            comment="JSON mapping of IdP claims to user fields",
        ),
        sa.Column(
            "created_at",
            sa.DateTime(),
            server_default=sa.text("now()"),
            nullable=False,
            comment="When this provider was created",
        ),
        sa.Column(
            "updated_at",
            sa.DateTime(),
            server_default=sa.text("now()"),
            nullable=False,
            comment="When this provider was last updated",
        ),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_index(
        op.f("ix_identity_providers_enabled"),
        "identity_providers",
        ["enabled"],
        unique=False,
    )
    op.create_index(
        op.f("ix_identity_providers_id"), "identity_providers", ["id"], unique=False
    )
    op.create_index(
        op.f("ix_identity_providers_slug"), "identity_providers", ["slug"], unique=True
    )

    # Create table users_identity_providers
    op.create_table(
        "users_identity_providers",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("user_id", sa.Integer(), nullable=False, comment="User ID"),
        sa.Column(
            "idp_id", sa.Integer(), nullable=False, comment="Identity Provider ID"
        ),
        sa.Column(
            "idp_subject",
            sa.String(length=500),
            nullable=False,
            comment="Subject/ID from the identity provider (unique per IdP)",
        ),
        sa.Column(
            "linked_at",
            sa.DateTime(),
            server_default=sa.text("now()"),
            nullable=False,
            comment="When this IdP was linked to the user",
        ),
        sa.Column(
            "last_login",
            sa.DateTime(),
            nullable=True,
            comment="Last time user logged in with this IdP",
        ),
        sa.ForeignKeyConstraint(
            ["idp_id"], ["identity_providers.id"], ondelete="CASCADE"
        ),
        sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_index(
        op.f("ix_user_identity_providers_id"),
        "user_identity_providers",
        ["id"],
        unique=False,
    )
    op.create_index(
        op.f("ix_user_identity_providers_idp_id"),
        "user_identity_providers",
        ["idp_id"],
        unique=False,
    )
    op.create_index(
        op.f("ix_user_identity_providers_user_id"),
        "user_identity_providers",
        ["user_id"],
        unique=False,
    )

    # Add additional columns to server_settings
    op.add_column(
        "server_settings",
        sa.Column(
            "sso_enabled",
            sa.Boolean(),
            nullable=True,
            comment="Enable SSO/IdP login (true - yes, false - no)",
        ),
    )
    op.execute(
        """
        UPDATE server_settings
        SET sso_enabled = false
        WHERE sso_enabled IS NULL;
    """
    )
    op.alter_column(
        "server_settings",
        "sso_enabled",
        nullable=False,
        comment="Enable SSO/IdP login (true - yes, false - no)",
        existing_type=sa.Boolean(),
    )
    op.add_column(
        "server_settings",
        sa.Column(
            "local_login_enabled",
            sa.Boolean(),
            nullable=True,
            comment="Allow local username/password login (true - yes, false - no)",
        ),
    )
    op.execute(
        """
        UPDATE server_settings
        SET local_login_enabled = true
        WHERE local_login_enabled IS NULL;
    """
    )
    op.alter_column(
        "server_settings",
        "local_login_enabled",
        nullable=False,
        comment="Allow local username/password login (true - yes, false - no)",
        existing_type=sa.Boolean(),
    )
    op.add_column(
        "server_settings",
        sa.Column(
            "sso_auto_redirect",
            sa.Boolean(),
            nullable=True,
            comment="Auto-redirect to SSO if only one IdP (true - yes, false - no)",
        ),
    )
    op.execute(
        """
        UPDATE server_settings
        SET sso_auto_redirect = false
        WHERE sso_auto_redirect IS NULL;
    """
    )
    op.alter_column(
        "server_settings",
        "sso_auto_redirect",
        nullable=False,
        comment="Auto-redirect to SSO if only one IdP (true - yes, false - no)",
        existing_type=sa.Boolean(),
    )
    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_column("server_settings", "sso_auto_redirect")
    op.drop_column("server_settings", "local_login_enabled")
    op.drop_column("server_settings", "sso_enabled")
    op.drop_index(
        op.f("ix_user_identity_providers_user_id"), table_name="user_identity_providers"
    )
    op.drop_index(
        op.f("ix_user_identity_providers_idp_id"), table_name="user_identity_providers"
    )
    op.drop_index(
        op.f("ix_user_identity_providers_id"), table_name="user_identity_providers"
    )
    op.drop_table("user_identity_providers")
    op.drop_index(op.f("ix_identity_providers_slug"), table_name="identity_providers")
    op.drop_index(op.f("ix_identity_providers_id"), table_name="identity_providers")
    op.drop_index(
        op.f("ix_identity_providers_enabled"), table_name="identity_providers"
    )
    op.drop_table("identity_providers")
    op.alter_column(
        "users_sessions",
        "refresh_token",
        existing_type=sa.String(length=255),
        type_=sa.VARCHAR(length=500),
        comment="Session refresh token",
        existing_comment="Session hashed refresh token",
        existing_nullable=False,
    )
    op.drop_index(op.f("ix_sign_up_tokens_user_id"), table_name="sign_up_tokens")
    # ### end Alembic commands ###
