# backend/app/auth/deps.py — 인증 의존성 (데모 모드 우회 포함)
from datetime import UTC, datetime

from fastapi import Depends, HTTPException, Request
from sqlmodel import Session, select

from ..config import get_settings
from ..db import get_session
from ..models import ApiToken, AuthSession, Person, UserCredential
from .tokens import hash_token, unsign_session_id

DEMO_USER_ID = "jiwoo"  # AUTH_ENABLED=false 일 때 고정 사용자(데모 무손상)


def current_user(request: Request, session: Session = Depends(get_session)) -> Person:
    st = get_settings()
    # 1) 데모 모드: 인증 끔 → 항상 지우
    if not st.auth_enabled:
        user = session.get(Person, DEMO_USER_ID)
        if user is None:
            raise HTTPException(500, "demo user 'jiwoo' missing — run_seed 필요")
        return user

    # 2) 쿠키 세션(웹) 우선
    raw = request.cookies.get(st.session_cookie_name)
    if raw:
        sid = unsign_session_id(raw)
        if sid:
            sess = session.get(AuthSession, sid)
            if sess and not sess.revoked:
                exp = sess.expires_at
                if exp.tzinfo is None:  # SQLite 는 naive 로 저장 → UTC 로 정규화
                    exp = exp.replace(tzinfo=UTC)
                if exp > datetime.now(UTC):
                    u = session.get(Person, sess.user_id)
                    if u:
                        return u

    # 3) 베어러 토큰(스크립트/모바일)
    auth = request.headers.get("Authorization", "")
    if auth.startswith("Bearer "):
        th = hash_token(auth[7:])
        tok = session.exec(select(ApiToken).where(ApiToken.token_hash == th)).first()
        if tok and not tok.revoked:
            tok.last_used_at = datetime.now(UTC)
            session.add(tok)
            session.commit()
            u = session.get(Person, tok.user_id)
            if u:
                return u

    raise HTTPException(status_code=401, detail="인증이 필요해요")


def require_admin(
    user: Person = Depends(current_user), session: Session = Depends(get_session)
) -> Person:
    cred = session.exec(select(UserCredential).where(UserCredential.user_id == user.id)).first()
    if not cred or cred.role != "admin":
        raise HTTPException(403, "관리자만 접근할 수 있어요")
    return user
