# backend/app/db.py
from sqlalchemy import event, text
from sqlmodel import Session, SQLModel, create_engine

from .config import get_settings

settings = get_settings()
_is_sqlite = settings.database_url.startswith("sqlite")
# SQLite + FastAPI: check_same_thread=False 필요. timeout = busy_timeout(초) — 쓰기 잠금 대기.
connect_args = {"check_same_thread": False, "timeout": 30} if _is_sqlite else {}
engine = create_engine(settings.database_url, echo=False, connect_args=connect_args)

if _is_sqlite:
    # WAL: 동기화(쓰기) 중에도 API(읽기)가 막히지 않게 — 'database is locked' 500 방지.
    @event.listens_for(engine, "connect")
    def _sqlite_pragmas(dbapi_conn, _rec):  # noqa: ANN001
        cur = dbapi_conn.cursor()
        cur.execute("PRAGMA journal_mode=WAL")
        cur.execute("PRAGMA busy_timeout=30000")
        cur.execute("PRAGMA synchronous=NORMAL")
        cur.close()

# 개발용 추가 컬럼(create_all 은 기존 테이블에 컬럼을 추가하지 못함).
# 운영은 alembic 마이그레이션을 쓰고, 여기서는 기존 SQLite DB 데이터를 보존한 채
# 누락 컬럼만 멱등하게 ALTER ADD 한다. 전부 additive + 기본값 보유라 안전.
_DEV_COLUMNS: list[tuple[str, str, str]] = [
    ("email", "cc", "TEXT NOT NULL DEFAULT ''"),
    ("email", "thread_id", "TEXT NOT NULL DEFAULT ''"),
    ("email", "body_html", "TEXT NOT NULL DEFAULT ''"),
    ("email", "received_at", "TIMESTAMP"),  # 수신 시각(최신순 정렬·표시). NULL 허용.
    ("email", "folder", "TEXT NOT NULL DEFAULT 'inbox'"),  # 시스템 폴더/버킷 슬러그
    ("email", "folder_name", "TEXT NOT NULL DEFAULT ''"),  # Outlook 커스텀 폴더 표시명
    ("email", "inference", "TEXT NOT NULL DEFAULT ''"),  # Outlook 집중/기타(focused/other)
    ("outbound_mail", "cc", "TEXT NOT NULL DEFAULT ''"),
    ("outbound_mail", "bcc", "TEXT NOT NULL DEFAULT ''"),
    ("outbound_mail", "attachments", "JSON NOT NULL DEFAULT '[]'"),
    ("cal_event", "rrule", "TEXT NOT NULL DEFAULT ''"),
    ("cal_event", "reminders", "JSON NOT NULL DEFAULT '[]'"),
    ("cal_event", "attendees", "JSON NOT NULL DEFAULT '[]'"),
    ("cal_event", "response_status", "TEXT NOT NULL DEFAULT ''"),
    ("task_comment", "edited_at", "DATETIME"),
]


def _ensure_dev_columns() -> None:
    if not settings.database_url.startswith("sqlite"):
        return
    with engine.begin() as conn:
        for table, column, ddl in _DEV_COLUMNS:
            rows = conn.exec_driver_sql(f"PRAGMA table_info({table})").fetchall()
            if not rows:  # 테이블 자체가 없으면 create_all 이 만들어 준다
                continue
            existing = {r[1] for r in rows}
            if column in existing:
                continue
            conn.execute(text(f'ALTER TABLE {table} ADD COLUMN {column} {ddl}'))


def init_db() -> None:
    SQLModel.metadata.create_all(engine)
    _ensure_dev_columns()


def get_session():
    with Session(engine) as session:
        yield session
