"""add loyalty system tables

Revision ID: add_loyalty_tables_001
Revises: ff515d77abbe
Create Date: 2024-01-01 00:00:00.000000

"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql

# revision identifiers, used by Alembic.
revision = 'add_loyalty_tables_001'
down_revision = 'ff515d77abbe'
branch_labels = None
depends_on = None


def upgrade() -> None:
    # Create loyalty_tiers table
    op.create_table(
        'loyalty_tiers',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('level', sa.Enum('bronze', 'silver', 'gold', 'platinum', name='tierlevel'), nullable=False),
        sa.Column('name', sa.String(length=100), nullable=False),
        sa.Column('description', sa.Text(), nullable=True),
        sa.Column('min_points', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('points_earn_rate', sa.Numeric(precision=5, scale=2), nullable=False, server_default='1.0'),
        sa.Column('discount_percentage', sa.Numeric(precision=5, scale=2), nullable=True),
        sa.Column('benefits', sa.Text(), nullable=True),
        sa.Column('icon', sa.String(length=255), nullable=True),
        sa.Column('color', sa.String(length=50), nullable=True),
        sa.Column('is_active', sa.Boolean(), nullable=False, server_default='1'),
        sa.Column('created_at', sa.DateTime(), nullable=False),
        sa.Column('updated_at', sa.DateTime(), nullable=False),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('level')
    )
    op.create_index(op.f('ix_loyalty_tiers_id'), 'loyalty_tiers', ['id'], unique=False)
    op.create_index(op.f('ix_loyalty_tiers_level'), 'loyalty_tiers', ['level'], unique=True)

    # Create user_loyalty table
    op.create_table(
        'user_loyalty',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('user_id', sa.Integer(), nullable=False),
        sa.Column('tier_id', sa.Integer(), nullable=False),
        sa.Column('total_points', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('lifetime_points', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('available_points', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('expired_points', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('referral_code', sa.String(length=50), nullable=True),
        sa.Column('referral_count', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('birthday', sa.Date(), nullable=True),
        sa.Column('anniversary_date', sa.Date(), nullable=True),
        sa.Column('last_points_earned_date', sa.DateTime(), nullable=True),
        sa.Column('tier_started_date', sa.DateTime(), nullable=True),
        sa.Column('next_tier_points_needed', sa.Integer(), nullable=True),
        sa.Column('created_at', sa.DateTime(), nullable=False),
        sa.Column('updated_at', sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
        sa.ForeignKeyConstraint(['tier_id'], ['loyalty_tiers.id']),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('user_id')
    )
    op.create_index(op.f('ix_user_loyalty_id'), 'user_loyalty', ['id'], unique=False)
    op.create_index(op.f('ix_user_loyalty_user_id'), 'user_loyalty', ['user_id'], unique=True)
    op.create_index(op.f('ix_user_loyalty_tier_id'), 'user_loyalty', ['tier_id'], unique=False)
    op.create_index(op.f('ix_user_loyalty_referral_code'), 'user_loyalty', ['referral_code'], unique=True)

    # Create loyalty_point_transactions table
    op.create_table(
        'loyalty_point_transactions',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('user_loyalty_id', sa.Integer(), nullable=False),
        sa.Column('booking_id', sa.Integer(), nullable=True),
        sa.Column('transaction_type', sa.Enum('earned', 'redeemed', 'expired', 'bonus', 'adjustment', name='transactiontype'), nullable=False),
        sa.Column('source', sa.Enum('booking', 'referral', 'birthday', 'anniversary', 'redemption', 'promotion', 'manual', name='transactionsource'), nullable=False),
        sa.Column('points', sa.Integer(), nullable=False),
        sa.Column('description', sa.Text(), nullable=True),
        sa.Column('expires_at', sa.DateTime(), nullable=True),
        sa.Column('reference_number', sa.String(length=100), nullable=True),
        sa.Column('created_at', sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(['user_loyalty_id'], ['user_loyalty.id'], ondelete='CASCADE'),
        sa.ForeignKeyConstraint(['booking_id'], ['bookings.id'], ondelete='SET NULL'),
        sa.PrimaryKeyConstraint('id')
    )
    op.create_index(op.f('ix_loyalty_point_transactions_id'), 'loyalty_point_transactions', ['id'], unique=False)
    op.create_index(op.f('ix_loyalty_point_transactions_user_loyalty_id'), 'loyalty_point_transactions', ['user_loyalty_id'], unique=False)
    op.create_index(op.f('ix_loyalty_point_transactions_booking_id'), 'loyalty_point_transactions', ['booking_id'], unique=False)
    op.create_index(op.f('ix_loyalty_point_transactions_transaction_type'), 'loyalty_point_transactions', ['transaction_type'], unique=False)
    op.create_index(op.f('ix_loyalty_point_transactions_created_at'), 'loyalty_point_transactions', ['created_at'], unique=False)

    # Create loyalty_rewards table
    op.create_table(
        'loyalty_rewards',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('name', sa.String(length=200), nullable=False),
        sa.Column('description', sa.Text(), nullable=True),
        sa.Column('reward_type', sa.Enum('discount', 'room_upgrade', 'amenity', 'cashback', 'voucher', name='rewardtype'), nullable=False),
        sa.Column('points_cost', sa.Integer(), nullable=False),
        sa.Column('discount_percentage', sa.Numeric(precision=5, scale=2), nullable=True),
        sa.Column('discount_amount', sa.Numeric(precision=10, scale=2), nullable=True),
        sa.Column('max_discount_amount', sa.Numeric(precision=10, scale=2), nullable=True),
        sa.Column('applicable_tier_id', sa.Integer(), nullable=True),
        sa.Column('min_booking_amount', sa.Numeric(precision=10, scale=2), nullable=True),
        sa.Column('icon', sa.String(length=255), nullable=True),
        sa.Column('image', sa.String(length=255), nullable=True),
        sa.Column('is_active', sa.Boolean(), nullable=False, server_default='1'),
        sa.Column('stock_quantity', sa.Integer(), nullable=True),
        sa.Column('redeemed_count', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('valid_from', sa.DateTime(), nullable=True),
        sa.Column('valid_until', sa.DateTime(), nullable=True),
        sa.Column('created_at', sa.DateTime(), nullable=False),
        sa.Column('updated_at', sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(['applicable_tier_id'], ['loyalty_tiers.id'], ondelete='SET NULL'),
        sa.PrimaryKeyConstraint('id')
    )
    op.create_index(op.f('ix_loyalty_rewards_id'), 'loyalty_rewards', ['id'], unique=False)
    op.create_index(op.f('ix_loyalty_rewards_reward_type'), 'loyalty_rewards', ['reward_type'], unique=False)

    # Create reward_redemptions table
    op.create_table(
        'reward_redemptions',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('user_loyalty_id', sa.Integer(), nullable=False),
        sa.Column('reward_id', sa.Integer(), nullable=False),
        sa.Column('booking_id', sa.Integer(), nullable=True),
        sa.Column('points_used', sa.Integer(), nullable=False),
        sa.Column('status', sa.Enum('pending', 'active', 'used', 'expired', 'cancelled', name='redemptionstatus'), nullable=False, server_default='pending'),
        sa.Column('code', sa.String(length=50), nullable=True),
        sa.Column('expires_at', sa.DateTime(), nullable=True),
        sa.Column('used_at', sa.DateTime(), nullable=True),
        sa.Column('created_at', sa.DateTime(), nullable=False),
        sa.Column('updated_at', sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(['user_loyalty_id'], ['user_loyalty.id'], ondelete='CASCADE'),
        sa.ForeignKeyConstraint(['reward_id'], ['loyalty_rewards.id'], ondelete='CASCADE'),
        sa.ForeignKeyConstraint(['booking_id'], ['bookings.id'], ondelete='SET NULL'),
        sa.PrimaryKeyConstraint('id'),
        sa.UniqueConstraint('code')
    )
    op.create_index(op.f('ix_reward_redemptions_id'), 'reward_redemptions', ['id'], unique=False)
    op.create_index(op.f('ix_reward_redemptions_user_loyalty_id'), 'reward_redemptions', ['user_loyalty_id'], unique=False)
    op.create_index(op.f('ix_reward_redemptions_reward_id'), 'reward_redemptions', ['reward_id'], unique=False)
    op.create_index(op.f('ix_reward_redemptions_booking_id'), 'reward_redemptions', ['booking_id'], unique=False)
    op.create_index(op.f('ix_reward_redemptions_status'), 'reward_redemptions', ['status'], unique=False)
    op.create_index(op.f('ix_reward_redemptions_code'), 'reward_redemptions', ['code'], unique=True)

    # Create referrals table
    op.create_table(
        'referrals',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('referrer_id', sa.Integer(), nullable=False),
        sa.Column('referred_user_id', sa.Integer(), nullable=False),
        sa.Column('referral_code', sa.String(length=50), nullable=False),
        sa.Column('booking_id', sa.Integer(), nullable=True),
        sa.Column('status', sa.Enum('pending', 'completed', 'rewarded', name='referralstatus'), nullable=False, server_default='pending'),
        sa.Column('referrer_points_earned', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('referred_points_earned', sa.Integer(), nullable=False, server_default='0'),
        sa.Column('completed_at', sa.DateTime(), nullable=True),
        sa.Column('rewarded_at', sa.DateTime(), nullable=True),
        sa.Column('created_at', sa.DateTime(), nullable=False),
        sa.ForeignKeyConstraint(['referrer_id'], ['user_loyalty.id'], ondelete='CASCADE'),
        sa.ForeignKeyConstraint(['referred_user_id'], ['users.id'], ondelete='CASCADE'),
        sa.ForeignKeyConstraint(['booking_id'], ['bookings.id'], ondelete='SET NULL'),
        sa.PrimaryKeyConstraint('id')
    )
    op.create_index(op.f('ix_referrals_id'), 'referrals', ['id'], unique=False)
    op.create_index(op.f('ix_referrals_referrer_id'), 'referrals', ['referrer_id'], unique=False)
    op.create_index(op.f('ix_referrals_referred_user_id'), 'referrals', ['referred_user_id'], unique=False)
    op.create_index(op.f('ix_referrals_referral_code'), 'referrals', ['referral_code'], unique=False)
    op.create_index(op.f('ix_referrals_booking_id'), 'referrals', ['booking_id'], unique=False)
    op.create_index(op.f('ix_referrals_status'), 'referrals', ['status'], unique=False)
    op.create_index(op.f('ix_referrals_created_at'), 'referrals', ['created_at'], unique=False)


def downgrade() -> None:
    op.drop_index(op.f('ix_referrals_created_at'), table_name='referrals')
    op.drop_index(op.f('ix_referrals_status'), table_name='referrals')
    op.drop_index(op.f('ix_referrals_booking_id'), table_name='referrals')
    op.drop_index(op.f('ix_referrals_referral_code'), table_name='referrals')
    op.drop_index(op.f('ix_referrals_referred_user_id'), table_name='referrals')
    op.drop_index(op.f('ix_referrals_referrer_id'), table_name='referrals')
    op.drop_index(op.f('ix_referrals_id'), table_name='referrals')
    op.drop_table('referrals')
    
    op.drop_index(op.f('ix_reward_redemptions_code'), table_name='reward_redemptions')
    op.drop_index(op.f('ix_reward_redemptions_status'), table_name='reward_redemptions')
    op.drop_index(op.f('ix_reward_redemptions_booking_id'), table_name='reward_redemptions')
    op.drop_index(op.f('ix_reward_redemptions_reward_id'), table_name='reward_redemptions')
    op.drop_index(op.f('ix_reward_redemptions_user_loyalty_id'), table_name='reward_redemptions')
    op.drop_index(op.f('ix_reward_redemptions_id'), table_name='reward_redemptions')
    op.drop_table('reward_redemptions')
    
    op.drop_index(op.f('ix_loyalty_rewards_reward_type'), table_name='loyalty_rewards')
    op.drop_index(op.f('ix_loyalty_rewards_id'), table_name='loyalty_rewards')
    op.drop_table('loyalty_rewards')
    
    op.drop_index(op.f('ix_loyalty_point_transactions_created_at'), table_name='loyalty_point_transactions')
    op.drop_index(op.f('ix_loyalty_point_transactions_transaction_type'), table_name='loyalty_point_transactions')
    op.drop_index(op.f('ix_loyalty_point_transactions_booking_id'), table_name='loyalty_point_transactions')
    op.drop_index(op.f('ix_loyalty_point_transactions_user_loyalty_id'), table_name='loyalty_point_transactions')
    op.drop_index(op.f('ix_loyalty_point_transactions_id'), table_name='loyalty_point_transactions')
    op.drop_table('loyalty_point_transactions')
    
    op.drop_index(op.f('ix_user_loyalty_referral_code'), table_name='user_loyalty')
    op.drop_index(op.f('ix_user_loyalty_tier_id'), table_name='user_loyalty')
    op.drop_index(op.f('ix_user_loyalty_user_id'), table_name='user_loyalty')
    op.drop_index(op.f('ix_user_loyalty_id'), table_name='user_loyalty')
    op.drop_table('user_loyalty')
    
    op.drop_index(op.f('ix_loyalty_tiers_level'), table_name='loyalty_tiers')
    op.drop_index(op.f('ix_loyalty_tiers_id'), table_name='loyalty_tiers')
    op.drop_table('loyalty_tiers')

