"""Add tree organization: tags, categories, folders, team admin

Revision ID: 005
Revises: 004
Create Date: 2026-02-01

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql


# revision identifiers, used by Alembic.
revision: str = '005'
down_revision: Union[str, None] = '004'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    # ===========================================
    # 1. Add is_team_admin to users
    # ===========================================
    op.add_column('users', sa.Column('is_team_admin', sa.Boolean(), nullable=False, server_default='false'))

    # ===========================================
    # 2. Create tree_categories table
    # ===========================================
    op.create_table(
        'tree_categories',
        sa.Column('id', postgresql.UUID(as_uuid=True), primary_key=True, server_default=sa.text('gen_random_uuid()')),
        sa.Column('name', sa.String(100), nullable=False),
        sa.Column('slug', sa.String(100), nullable=False),
        sa.Column('description', sa.Text(), nullable=True),
        sa.Column('team_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('teams.id', ondelete='CASCADE'), nullable=True),
        sa.Column('display_order', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('is_active', sa.Boolean(), nullable=False, server_default='true'),
        sa.Column('created_by', postgresql.UUID(as_uuid=True), sa.ForeignKey('users.id', ondelete='SET NULL'), nullable=True),
        sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
        sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
        sa.UniqueConstraint('slug', 'team_id', name='uq_tree_categories_slug_team')
    )
    op.create_index('ix_tree_categories_team_id', 'tree_categories', ['team_id'])
    op.create_index('ix_tree_categories_slug', 'tree_categories', ['slug'])
    op.create_index('ix_tree_categories_display_order', 'tree_categories', ['display_order'])

    # ===========================================
    # 3. Create tree_tags table
    # ===========================================
    op.create_table(
        'tree_tags',
        sa.Column('id', postgresql.UUID(as_uuid=True), primary_key=True, server_default=sa.text('gen_random_uuid()')),
        sa.Column('name', sa.String(50), nullable=False),
        sa.Column('slug', sa.String(50), nullable=False),
        sa.Column('team_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('teams.id', ondelete='CASCADE'), nullable=True),
        sa.Column('usage_count', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('created_by', postgresql.UUID(as_uuid=True), sa.ForeignKey('users.id', ondelete='SET NULL'), nullable=True),
        sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
        sa.UniqueConstraint('slug', 'team_id', name='uq_tree_tags_slug_team')
    )
    op.create_index('ix_tree_tags_slug', 'tree_tags', ['slug'])
    op.create_index('ix_tree_tags_team_id', 'tree_tags', ['team_id'])
    op.create_index('ix_tree_tags_usage_count', 'tree_tags', ['usage_count'])

    # ===========================================
    # 4. Create tree_tag_assignments junction table
    # ===========================================
    op.create_table(
        'tree_tag_assignments',
        sa.Column('tree_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('trees.id', ondelete='CASCADE'), primary_key=True),
        sa.Column('tag_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('tree_tags.id', ondelete='CASCADE'), primary_key=True),
        sa.Column('assigned_by', postgresql.UUID(as_uuid=True), sa.ForeignKey('users.id', ondelete='SET NULL'), nullable=True),
        sa.Column('assigned_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()'))
    )
    op.create_index('ix_tree_tag_assignments_tree_id', 'tree_tag_assignments', ['tree_id'])
    op.create_index('ix_tree_tag_assignments_tag_id', 'tree_tag_assignments', ['tag_id'])

    # ===========================================
    # 5. Create user_folders table
    # ===========================================
    op.create_table(
        'user_folders',
        sa.Column('id', postgresql.UUID(as_uuid=True), primary_key=True, server_default=sa.text('gen_random_uuid()')),
        sa.Column('user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('users.id', ondelete='CASCADE'), nullable=False),
        sa.Column('name', sa.String(100), nullable=False),
        sa.Column('color', sa.String(7), nullable=False, server_default='#6366f1'),
        sa.Column('icon', sa.String(50), nullable=False, server_default='folder'),
        sa.Column('display_order', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('created_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
        sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
        sa.UniqueConstraint('user_id', 'name', name='uq_user_folders_user_name')
    )
    op.create_index('ix_user_folders_user_id', 'user_folders', ['user_id'])

    # ===========================================
    # 6. Create user_folder_trees junction table
    # ===========================================
    op.create_table(
        'user_folder_trees',
        sa.Column('folder_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('user_folders.id', ondelete='CASCADE'), primary_key=True),
        sa.Column('tree_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('trees.id', ondelete='CASCADE'), primary_key=True),
        sa.Column('added_at', sa.DateTime(timezone=True), nullable=False, server_default=sa.text('now()')),
        sa.Column('display_order', sa.Integer(), nullable=False, server_default='0')
    )
    op.create_index('ix_user_folder_trees_folder_id', 'user_folder_trees', ['folder_id'])
    op.create_index('ix_user_folder_trees_tree_id', 'user_folder_trees', ['tree_id'])

    # ===========================================
    # 7. Add category_id to trees table
    # ===========================================
    op.add_column('trees', sa.Column('category_id', postgresql.UUID(as_uuid=True), nullable=True))
    op.create_foreign_key('fk_trees_category_id', 'trees', 'tree_categories', ['category_id'], ['id'], ondelete='SET NULL')
    op.create_index('ix_trees_category_id', 'trees', ['category_id'])

    # ===========================================
    # 8. Seed default global categories
    # ===========================================
    op.execute("""
        INSERT INTO tree_categories (name, slug, description, display_order, team_id) VALUES
        ('Help Desk', 'help-desk', 'Tier 1 support - password resets, basic troubleshooting', 1, NULL),
        ('Desktop Support', 'desktop-support', 'Tier 2 support - workstation issues, software problems', 2, NULL),
        ('Systems Administration', 'systems-administration', 'Tier 3 support - servers, Active Directory, infrastructure', 3, NULL),
        ('Networking', 'networking', 'Network connectivity, VPN, firewall, DNS/DHCP', 4, NULL),
        ('Security', 'security', 'Security incidents, access issues, compliance', 5, NULL),
        ('Cloud & Microsoft 365', 'cloud-m365', 'Microsoft 365, Azure, cloud services', 6, NULL),
        ('Backup & Recovery', 'backup-recovery', 'Backup systems, disaster recovery, data restoration', 7, NULL),
        ('Printing', 'printing', 'Print servers, printers, drivers, spooler issues', 8, NULL)
    """)

    # ===========================================
    # 9. Migrate existing category strings to new system
    # ===========================================
    # First, create tags from existing categories
    op.execute("""
        INSERT INTO tree_tags (name, slug, team_id, usage_count)
        SELECT DISTINCT
            category as name,
            LOWER(REGEXP_REPLACE(REGEXP_REPLACE(category, '[^a-zA-Z0-9 ]', '', 'g'), ' +', '-', 'g')) as slug,
            NULL::uuid as team_id,
            COUNT(*) OVER (PARTITION BY category) as usage_count
        FROM trees
        WHERE category IS NOT NULL AND category != ''
        ON CONFLICT (slug, team_id) DO NOTHING
    """)

    # Assign tags to trees based on their old category
    op.execute("""
        INSERT INTO tree_tag_assignments (tree_id, tag_id)
        SELECT t.id as tree_id, tt.id as tag_id
        FROM trees t
        JOIN tree_tags tt ON tt.slug = LOWER(REGEXP_REPLACE(REGEXP_REPLACE(t.category, '[^a-zA-Z0-9 ]', '', 'g'), ' +', '-', 'g'))
            AND tt.team_id IS NULL
        WHERE t.category IS NOT NULL AND t.category != ''
        ON CONFLICT DO NOTHING
    """)


def downgrade() -> None:
    # Drop foreign key and column from trees
    op.drop_constraint('fk_trees_category_id', 'trees', type_='foreignkey')
    op.drop_index('ix_trees_category_id', table_name='trees')
    op.drop_column('trees', 'category_id')

    # Drop user_folder_trees
    op.drop_index('ix_user_folder_trees_tree_id', table_name='user_folder_trees')
    op.drop_index('ix_user_folder_trees_folder_id', table_name='user_folder_trees')
    op.drop_table('user_folder_trees')

    # Drop user_folders
    op.drop_index('ix_user_folders_user_id', table_name='user_folders')
    op.drop_table('user_folders')

    # Drop tree_tag_assignments
    op.drop_index('ix_tree_tag_assignments_tag_id', table_name='tree_tag_assignments')
    op.drop_index('ix_tree_tag_assignments_tree_id', table_name='tree_tag_assignments')
    op.drop_table('tree_tag_assignments')

    # Drop tree_tags
    op.drop_index('ix_tree_tags_usage_count', table_name='tree_tags')
    op.drop_index('ix_tree_tags_team_id', table_name='tree_tags')
    op.drop_index('ix_tree_tags_slug', table_name='tree_tags')
    op.drop_table('tree_tags')

    # Drop tree_categories
    op.drop_index('ix_tree_categories_display_order', table_name='tree_categories')
    op.drop_index('ix_tree_categories_slug', table_name='tree_categories')
    op.drop_index('ix_tree_categories_team_id', table_name='tree_categories')
    op.drop_table('tree_categories')

    # Remove is_team_admin from users
    op.drop_column('users', 'is_team_admin')
