"""add tree forking support with lineage tracking

Revision ID: 022
Revises: 021
Create Date: 2026-02-07

Adds fork relationship and lineage tracking to trees table:
- parent_tree_id: Points to immediate parent tree (NULL for root trees)
- fork_reason: Optional engineer note explaining fork purpose
- parent_updated_at: Snapshot of parent's updated_at at fork time
- root_tree_id: Points to original tree at root of fork chain
- fork_depth: How many forks deep (1 = direct fork, 2 = fork of fork, etc.)

Fork on parent delete behavior: SET NULL (orphaned forks survive)
Root tree delete behavior: SET NULL (lineage preserved via fork_depth)
"""
from typing import Sequence, Union

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


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


def upgrade() -> None:
    # Add fork tracking columns
    op.add_column('trees', sa.Column('parent_tree_id', UUID(as_uuid=True), nullable=True))
    op.add_column('trees', sa.Column('fork_reason', sa.String(255), nullable=True))
    op.add_column('trees', sa.Column('parent_updated_at', sa.DateTime(timezone=True), nullable=True))

    # Add fork lineage columns
    op.add_column('trees', sa.Column('root_tree_id', UUID(as_uuid=True), nullable=True))
    op.add_column('trees', sa.Column('fork_depth', sa.Integer, nullable=False, server_default='0'))

    # Add foreign key constraints
    op.create_foreign_key(
        'fk_trees_parent_tree_id',
        'trees', 'trees',
        ['parent_tree_id'], ['id'],
        ondelete='SET NULL'
    )
    op.create_foreign_key(
        'fk_trees_root_tree_id',
        'trees', 'trees',
        ['root_tree_id'], ['id'],
        ondelete='SET NULL'
    )

    # Add indexes for fork queries
    op.create_index('ix_trees_parent_tree_id', 'trees', ['parent_tree_id'])
    op.create_index('ix_trees_root_tree_id', 'trees', ['root_tree_id'])

    # Composite index for fork analytics (descendants + depth sorting)
    op.create_index('ix_trees_fork_analytics', 'trees', ['root_tree_id', 'fork_depth'])


def downgrade() -> None:
    op.drop_index('ix_trees_fork_analytics', table_name='trees')
    op.drop_index('ix_trees_root_tree_id', table_name='trees')
    op.drop_index('ix_trees_parent_tree_id', table_name='trees')
    op.drop_constraint('fk_trees_root_tree_id', 'trees', type_='foreignkey')
    op.drop_constraint('fk_trees_parent_tree_id', 'trees', type_='foreignkey')
    op.drop_column('trees', 'fork_depth')
    op.drop_column('trees', 'root_tree_id')
    op.drop_column('trees', 'parent_updated_at')
    op.drop_column('trees', 'fork_reason')
    op.drop_column('trees', 'parent_tree_id')
