"""Add product_images table and update product model

Revision ID: ec77c5cf5215
Revises: fa37fa53111f
Create Date: 2025-02-09 20:55:49.661026

"""
from typing import Sequence, Union

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

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

def table_exists(table_name: str) -> bool:
    bind = op.get_bind()
    inspector = sa.inspect(bind)
    return table_name in inspector.get_table_names()

def column_exists(table_name: str, column_name: str) -> bool:
    bind = op.get_bind()
    inspector = sa.inspect(bind)
    columns = inspector.get_columns(table_name)
    return any(col["name"] == column_name for col in columns)

def upgrade() -> None:
    # 먼저 product_categories 테이블을 생성 (존재하지 않을 때만)
    if not table_exists("product_categories"):
        op.create_table(
            'product_categories',
            sa.Column('id', sa.Integer, primary_key=True, autoincrement=True),
            sa.Column('code', sa.String(3), unique=True, nullable=False),
            sa.Column('name', sa.String(50), nullable=False),
            sa.Column('description', sa.Text, nullable=True),
            sa.Column('created_at', sa.DateTime, nullable=False, server_default=sa.func.now()),
            sa.Column('updated_at', sa.DateTime, nullable=False, server_default=sa.func.now(), onupdate=sa.func.now())
        )

    # 제품 이미지 테이블 생성 (존재하지 않을 때만)
    if not table_exists("product_images"):
        op.create_table(
            'product_images',
            sa.Column('id', sa.Integer, primary_key=True, autoincrement=True),
            sa.Column('product_id', mysql.BIGINT(unsigned=True), sa.ForeignKey('products.id'), nullable=False),
            sa.Column('image_url', sa.String(255), nullable=False),
            sa.Column('sort_order', sa.Integer, nullable=False, server_default='0'),
            sa.Column('created_at', sa.DateTime, nullable=False, server_default=sa.func.now()),
            sa.Column('updated_at', sa.DateTime, nullable=False, server_default=sa.func.now(), onupdate=sa.func.now())
        )
        op.execute("""
            INSERT INTO product_images (product_id, image_url, sort_order, created_at, updated_at)
            SELECT id, image_url, 0, created_at, updated_at FROM products WHERE image_url IS NOT NULL
        """)
    else:
        print("product_images table already exists, skipping creation.")

    # products 테이블의 카테고리 구조 업데이트
    # 1. 새 컬럼 'category_id'를 임시로 nullable하게 추가 (이미 존재하지 않을 때만)
    if not column_exists('products', 'category_id'):
        op.add_column('products', sa.Column('category_id', sa.Integer(), nullable=True))
    else:
        print("products 테이블에 'category_id' 컬럼이 이미 존재합니다. 추가를 건너뜁니다.")

    # 2. 기존의 category 컬럼 값을 product_categories 테이블의 code와 매핑하여 category_id에 채움
    op.execute("""
        UPDATE products p
        JOIN product_categories pc ON p.category = pc.code
        SET p.category_id = pc.id
    """)
    # 3. 매핑되지 않은 데이터에 대해 기본값(예: 1) 설정 (필요에 따라 조정)
    op.execute("""
        UPDATE products
        SET category_id = 1
        WHERE category_id IS NULL
    """)
    # 4. category_id 컬럼을 NOT NULL로 변경
    op.alter_column('products', 'category_id',
                    existing_type=sa.Integer(),
                    nullable=False)
    # 5. 기존의 'category'와 'sub_category' 컬럼 제거
    op.drop_column('products', 'category')
    op.drop_column('products', 'sub_category')


def downgrade() -> None:
    # products 테이블의 이전 상태로 복원
    # 1. 기존 컬럼들을 다시 추가
    op.add_column('products', sa.Column('sub_category', sa.String(50), nullable=True))
    op.add_column('products', sa.Column('category', sa.String(50), nullable=False))
    # 2. product_categories 테이블과의 조인을 통해 데이터를 복구
    op.execute("""
        UPDATE products p
        JOIN product_categories pc ON p.category_id = pc.id
        SET p.category = pc.code
    """)
    # 3. 새 컬럼 'category_id' 제거
    op.drop_column('products', 'category_id')
    # 제품 이미지 테이블 제거
    op.drop_table('product_images')
    # 생성했던 product_categories 테이블 제거 (실제 환경에 따라 보존 필요할 수 있음)
    op.drop_table('product_categories')
