#!/bin/bash
# migrate_to_postgres.sh — SQLite → PostgreSQL 데이터 마이그레이션
#
# 사용법:
#   bash migrate_to_postgres.sh [sqlite_path] [pg_url]
#
# 예시:
#   bash migrate_to_postgres.sh \
#     sqlite:///./guardia.db \
#     postgresql+asyncpg://guardia:guardia@localhost:5432/guardia
#
# 전제조건:
#   - Python 3.11+, pip install alembic asyncpg psycopg2-binary sqlalchemy
#   - PostgreSQL 서버 실행 중, DB/사용자 사전 생성
#
# 절차:
#   1. PostgreSQL 스키마 생성 (Alembic 마이그레이션)
#   2. SQLite 데이터 덤프 (pg_dump 불가 → Python으로 직접 이관)
#   3. 검증 (레코드 수 비교)

set -euo pipefail

SQLITE_URL="${1:-sqlite:///./guardia.db}"
PG_URL="${2:-postgresql+psycopg2://guardia:guardia@localhost:5432/guardia}"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ITSM_DIR="$(dirname "$SCRIPT_DIR")"

echo "=================================================="
echo " GUARDiA PostgreSQL 마이그레이션"
echo "=================================================="
echo " SQLite: $SQLITE_URL"
echo " PostgreSQL: ${PG_URL//:*@/:***@}"  # 비밀번호 마스킹
echo ""

# ── Step 1: Alembic 스키마 마이그레이션 ─────────────────────────────────────
echo "[1/3] PostgreSQL 스키마 생성 중..."
cd "$ITSM_DIR"

if [ -f "alembic.ini" ]; then
    # asyncpg를 psycopg2로 변환 (Alembic은 동기 연결 사용)
    PG_SYNC_URL="${PG_URL/asyncpg/psycopg2}"
    ALEMBIC_INI_BACKUP="alembic.ini.bak"
    cp alembic.ini "$ALEMBIC_INI_BACKUP"
    sed -i "s|sqlalchemy.url = .*|sqlalchemy.url = $PG_SYNC_URL|" alembic.ini
    python -m alembic upgrade head
    mv "$ALEMBIC_INI_BACKUP" alembic.ini
    echo "  ✓ Alembic 마이그레이션 완료"
else
    echo "  ⚠ alembic.ini를 찾을 수 없습니다. 스키마 생성은 Python으로 대체합니다."
    python -c "
import asyncio, os
os.environ['DATABASE_URL'] = '$PG_URL'
from database import engine, Base
import models  # noqa: F401
async def create():
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
asyncio.run(create())
print('  ✓ 스키마 생성 완료 (SQLAlchemy)')
"
fi

# ── Step 2: 데이터 이관 ─────────────────────────────────────────────────────
echo "[2/3] 데이터 이관 중..."
python -c "
import asyncio, os, sys
SQLITE_URL = '$SQLITE_URL'
PG_URL     = '$PG_URL'

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
from sqlalchemy import text, inspect

# SQLite URL 정규화 (asyncio 드라이버 사용)
if SQLITE_URL.startswith('sqlite:///'):
    SQLITE_ASYNC = SQLITE_URL.replace('sqlite:///', 'sqlite+aiosqlite:///')
else:
    SQLITE_ASYNC = SQLITE_URL

src_engine = create_async_engine(SQLITE_ASYNC, echo=False)
dst_engine = create_async_engine(PG_URL, echo=False)

SrcSession = sessionmaker(src_engine, class_=AsyncSession, expire_on_commit=False)
DstSession = sessionmaker(dst_engine, class_=AsyncSession, expire_on_commit=False)

SKIP_TABLES = set()

async def migrate():
    async with src_engine.connect() as src_conn:
        table_names = await src_conn.run_sync(
            lambda conn: inspect(conn).get_table_names()
        )

    total_copied = 0
    for table in table_names:
        if table in SKIP_TABLES:
            continue
        try:
            async with src_engine.connect() as src_conn:
                result = await src_conn.execute(text(f'SELECT * FROM {table}'))
                rows = result.mappings().all()
                if not rows:
                    continue

            async with dst_engine.begin() as dst_conn:
                # TRUNCATE (재실행 안전성)
                await dst_conn.execute(text(f'TRUNCATE TABLE {table} RESTART IDENTITY CASCADE'))
                await dst_conn.execute(
                    text(f'INSERT INTO {table} ({chr(44).join(rows[0].keys())}) VALUES ({chr(44).join([\":\" + k for k in rows[0].keys()])})'),
                    [dict(r) for r in rows],
                )
            total_copied += len(rows)
            print(f'  ✓ {table}: {len(rows)}건 이관')
        except Exception as e:
            print(f'  ✗ {table} 이관 실패: {e}', file=sys.stderr)

    print(f'  총 {total_copied}건 이관 완료')

asyncio.run(migrate())
"

# ── Step 3: 검증 ─────────────────────────────────────────────────────────────
echo "[3/3] 데이터 검증 중..."
python -c "
import asyncio
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy import text, inspect

SQLITE_ASYNC = '$SQLITE_URL'.replace('sqlite:///', 'sqlite+aiosqlite:///')
PG_URL       = '$PG_URL'

src_engine = create_async_engine(SQLITE_ASYNC)
dst_engine = create_async_engine(PG_URL)

async def verify():
    ok = True
    async with src_engine.connect() as src_conn:
        tables = await src_conn.run_sync(lambda c: inspect(c).get_table_names())
    for table in tables:
        try:
            async with src_engine.connect() as c:
                src_cnt = (await c.execute(text(f'SELECT COUNT(*) FROM {table}'))).scalar()
            async with dst_engine.connect() as c:
                dst_cnt = (await c.execute(text(f'SELECT COUNT(*) FROM {table}'))).scalar()
            match = '✓' if src_cnt == dst_cnt else '✗'
            print(f'  {match} {table}: SQLite={src_cnt} PostgreSQL={dst_cnt}')
            if src_cnt != dst_cnt:
                ok = False
        except Exception as e:
            print(f'  - {table}: 검증 스킵 ({e})')
    if ok:
        print('  ✅ 검증 통과 — 마이그레이션 성공')
    else:
        print('  ❌ 일부 테이블 불일치 — 수동 확인 필요')
        exit(1)

asyncio.run(verify())
"

echo ""
echo "=================================================="
echo " 마이그레이션 완료!"
echo " DATABASE_URL 환경변수를 변경하여 PostgreSQL로 전환하세요."
echo " 예: export DATABASE_URL='$PG_URL'"
echo "=================================================="
