"""v0.10.0 migration

Revision ID: 4ac2cc4f4e41
Revises: 7217cc0eee8c
Create Date: 2025-02-27 15:43:18.729569

"""

from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision: str = "4ac2cc4f4e41"
down_revision: Union[str, None] = "7217cc0eee8c"
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! ###
    # Add default_activity_visibility column to users table
    op.add_column(
        "users",
        sa.Column(
            "default_activity_visibility",
            sa.Integer(),
            nullable=False,
            server_default=sa.text("0"),
            comment="0 - public, 1 - followers, 2 - private",
        ),
    )
    # Add login_photo_set column to server_settings table
    op.add_column(
        "server_settings",
        sa.Column(
            "login_photo_set",
            sa.Boolean(),
            nullable=True,
            comment="Is login photo set (true - yes, false - no)",
        ),
    )
    # Set default value for existing records
    op.execute(
        """
        UPDATE server_settings
        SET login_photo_set = FALSE
        """
    )
    # Make the column non-nullable now that all rows have a value
    op.alter_column(
        "server_settings",
        "login_photo_set",
        existing_type=sa.Boolean(),
        nullable=False,
    )
    # Create activities_laps table
    op.create_table(
        "activity_laps",
        sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
        sa.Column(
            "activity_id",
            sa.Integer(),
            nullable=False,
            comment="Activity ID that the activity lap belongs",
        ),
        sa.Column(
            "start_time",
            sa.DateTime(),
            nullable=False,
            comment="Lap start date (DATETIME)",
        ),
        sa.Column(
            "start_position_lat",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap start position latitude",
        ),
        sa.Column(
            "start_position_long",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap start position longitude",
        ),
        sa.Column(
            "end_position_lat",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap end position latitude",
        ),
        sa.Column(
            "end_position_long",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap end position longitude",
        ),
        sa.Column(
            "total_elapsed_time",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap total elapsed time (s)",
        ),
        sa.Column(
            "total_timer_time",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap total timer time (s)",
        ),
        sa.Column(
            "total_distance",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap total distance (m)",
        ),
        sa.Column(
            "total_cycles", sa.Integer(), nullable=True, comment="Lap total cycles"
        ),
        sa.Column(
            "total_calories", sa.Integer(), nullable=True, comment="Lap total calories"
        ),
        sa.Column(
            "avg_heart_rate",
            sa.Integer(),
            nullable=True,
            comment="Lap average heart rate",
        ),
        sa.Column(
            "max_heart_rate",
            sa.Integer(),
            nullable=True,
            comment="Lap maximum heart rate",
        ),
        sa.Column(
            "avg_cadence", sa.Integer(), nullable=True, comment="Lap average cadence"
        ),
        sa.Column(
            "max_cadence", sa.Integer(), nullable=True, comment="Lap maximum cadence"
        ),
        sa.Column(
            "avg_power", sa.Integer(), nullable=True, comment="Lap average power"
        ),
        sa.Column(
            "max_power", sa.Integer(), nullable=True, comment="Lap maximum power"
        ),
        sa.Column(
            "total_ascent", sa.Integer(), nullable=True, comment="Lap total ascent (m)"
        ),
        sa.Column(
            "total_descent",
            sa.Integer(),
            nullable=True,
            comment="Lap total descent (m)",
        ),
        sa.Column(
            "intensity", sa.String(length=250), nullable=True, comment="Lap intensity"
        ),
        sa.Column(
            "lap_trigger", sa.String(length=250), nullable=True, comment="Lap trigger"
        ),
        sa.Column("sport", sa.String(length=250), nullable=True, comment="Lap sport"),
        sa.Column(
            "sub_sport", sa.String(length=250), nullable=True, comment="Lap sub sport"
        ),
        sa.Column(
            "normalized_power",
            sa.Integer(),
            nullable=True,
            comment="Lap normalized power",
        ),
        sa.Column("total_work", sa.Integer(), nullable=True, comment="Lap total work"),
        sa.Column(
            "avg_vertical_oscillation",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap average vertical oscillation",
        ),
        sa.Column(
            "avg_stance_time",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap average stance time",
        ),
        sa.Column(
            "avg_fractional_cadence",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap average fractional cadence",
        ),
        sa.Column(
            "max_fractional_cadence",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap maximum fractional cadence",
        ),
        sa.Column(
            "enhanced_avg_pace",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap enhanced average pace",
        ),
        sa.Column(
            "enhanced_avg_speed",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap enhanced average speed",
        ),
        sa.Column(
            "enhanced_max_pace",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap enhanced maximum pace",
        ),
        sa.Column(
            "enhanced_max_speed",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap enhanced maximum speed",
        ),
        sa.Column(
            "enhanced_min_altitude",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap enhanced minimum altitude",
        ),
        sa.Column(
            "enhanced_max_altitude",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap enhanced maximum altitude",
        ),
        sa.Column(
            "avg_vertical_ratio",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap average vertical ratio",
        ),
        sa.Column(
            "avg_step_length",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Lap average step length",
        ),
        sa.ForeignKeyConstraint(["activity_id"], ["activities.id"], ondelete="CASCADE"),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_index(
        op.f("ix_activity_laps_activity_id"),
        "activity_laps",
        ["activity_id"],
        unique=False,
    )
    # Create activity_exercise_titles table
    op.create_table(
        "activity_exercise_titles",
        sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
        sa.Column(
            "exercise_category",
            sa.Integer(),
            nullable=False,
            comment="Exercise category",
        ),
        sa.Column(
            "exercise_name", sa.Integer(), nullable=False, comment="Exercise name ID"
        ),
        sa.Column(
            "wkt_step_name",
            sa.String(length=250),
            nullable=False,
            comment="WKT step name (May include spaces)",
        ),
        sa.PrimaryKeyConstraint("id"),
    )
    # Create activity_workout_steps table
    op.create_table(
        "activity_workout_steps",
        sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
        sa.Column(
            "activity_id",
            sa.Integer(),
            nullable=False,
            comment="Activity ID that the activity workout steps belongs",
        ),
        sa.Column(
            "message_index",
            sa.Integer(),
            nullable=False,
            comment="Workout step message index",
        ),
        sa.Column(
            "duration_type",
            sa.String(length=250),
            nullable=False,
            comment="Workout step duration type",
        ),
        sa.Column(
            "duration_value",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Workout step duration value",
        ),
        sa.Column(
            "target_type",
            sa.String(length=250),
            nullable=True,
            comment="Workout step target type",
        ),
        sa.Column(
            "target_value",
            sa.Integer(),
            nullable=True,
            comment="Workout step target value",
        ),
        sa.Column(
            "intensity",
            sa.String(length=250),
            nullable=True,
            comment="Workout step intensity type",
        ),
        sa.Column(
            "notes", sa.String(length=250), nullable=True, comment="Workout step notes"
        ),
        sa.Column(
            "exercise_category",
            sa.Integer(),
            nullable=True,
            comment="Workout step exercise category",
        ),
        sa.Column(
            "exercise_name", sa.Integer(), nullable=True, comment="Exercise name ID"
        ),
        sa.Column(
            "exercise_weight",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Workout step exercise weight",
        ),
        sa.Column(
            "weight_display_unit",
            sa.String(length=250),
            nullable=True,
            comment="Workout step weight display unit",
        ),
        sa.Column(
            "secondary_target_value",
            sa.String(length=250),
            nullable=True,
            comment="Workout step secondary target value",
        ),
        sa.ForeignKeyConstraint(["activity_id"], ["activities.id"], ondelete="CASCADE"),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_index(
        op.f("ix_activity_workout_steps_activity_id"),
        "activity_workout_steps",
        ["activity_id"],
        unique=False,
    )
    # Create activity_sets table
    op.create_table(
        "activity_sets",
        sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
        sa.Column(
            "activity_id",
            sa.Integer(),
            nullable=False,
            comment="Activity ID that the activity lap belongs",
        ),
        sa.Column(
            "duration",
            sa.DECIMAL(precision=20, scale=10),
            nullable=False,
            comment="Workout set duration",
        ),
        sa.Column(
            "repetitions", sa.Integer(), nullable=True, comment="Repetitions number"
        ),
        sa.Column(
            "weight",
            sa.DECIMAL(precision=20, scale=10),
            nullable=True,
            comment="Workout set exercise weight",
        ),
        sa.Column(
            "set_type",
            sa.String(length=250),
            nullable=False,
            comment="Workout set type",
        ),
        sa.Column(
            "start_time",
            sa.DateTime(),
            nullable=False,
            comment="Workout set start date (DATETIME)",
        ),
        sa.Column("category", sa.Integer(), nullable=True, comment="Category name"),
        sa.Column(
            "category_subtype",
            sa.Integer(),
            nullable=True,
            comment="Category sub type number",
        ),
        sa.ForeignKeyConstraint(["activity_id"], ["activities.id"], ondelete="CASCADE"),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_index(
        op.f("ix_activity_sets_activity_id"),
        "activity_sets",
        ["activity_id"],
        unique=False,
    )
    # Alter gear column gear_type to include racquet in comment
    op.alter_column(
        "gear",
        "gear_type",
        existing_type=sa.INTEGER(),
        comment="Gear type (1 - bike, 2 - shoes, 3 - wetsuit, 4 - racquet)",
        existing_comment="Gear type (1 - bike, 2 - shoes, 3 - wetsuit)",
        existing_nullable=False,
    )
    # Add column tennis_gear_id to users_default_gear table
    op.add_column(
        "users_default_gear",
        sa.Column(
            "tennis_gear_id",
            sa.Integer(),
            nullable=True,
            comment="Gear ID that the default tennis activity type belongs",
        ),
    )
    op.create_index(
        op.f("ix_users_default_gear_tennis_gear_id"),
        "users_default_gear",
        ["tennis_gear_id"],
        unique=False,
    )
    op.create_foreign_key(
        None,
        "users_default_gear",
        "gear",
        ["tennis_gear_id"],
        ["id"],
        ondelete="SET NULL",
    )
    # Create migration record
    op.execute(
        """
    INSERT INTO migrations (id, name, description, executed) VALUES
    (3, 'v0.10.0', 'Process activity laps for existing activities if possible', false);
    """
    )
    # ### end Alembic commands ###


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    # Drop migration record
    op.execute(
        """
    DELETE FROM migrations 
    WHERE id = 3;
    """
    )
    # Drop foreign key constraint from users_default_gear table
    op.drop_constraint(None, "users_default_gear", type_="foreignkey")
    op.drop_index(
        op.f("ix_users_default_gear_tennis_gear_id"), table_name="users_default_gear"
    )
    op.drop_column("users_default_gear", "tennis_gear_id")
    # Alter gear column gear_type to remove racquet from comment
    op.alter_column(
        "gear",
        "gear_type",
        existing_type=sa.INTEGER(),
        comment="Gear type (1 - bike, 2 - shoes, 3 - wetsuit)",
        existing_comment="Gear type (1 - bike, 2 - shoes, 3 - wetsuit, 4 - racquet)",
        existing_nullable=False,
    )
    # Drop activity_sets table
    op.drop_table("activity_sets")
    # Drop activity_workout_steps table
    op.drop_table("activity_workout_steps")
    # Drop activity_exercise_titles table
    op.drop_table("activity_exercise_titles")
    # Drop activities_laps table
    op.drop_table("activity_laps")
    # Drop default_activity_visibility column from users table
    op.drop_column("users", "default_activity_visibility")
    # ### end Alembic commands ###
