# utils/user_ref.py — 업무 user_id(String) 조회·정규화
"""세션 및 연관 테이블은 User.user_id(문자, 최대 20자)를 사용합니다."""
import re
from typing import Any, Optional

from src.models.user import User


def normalize_business_user_id(raw: Optional[str]) -> str:
    """user_id@domain 형태면 @ 앞 로컬 파트만, 길이는 DB 제한(20)에 맞춤."""
    if not raw:
        return ""
    s = str(raw).strip()
    if "@" in s:
        s = s.split("@", 1)[0].strip()
    return s[:20] if len(s) > 20 else s


def allocate_unique_user_id_from_email(email: str, username: Optional[str] = None) -> str:
    """이메일 로컬 파트 기준 user_id 할당. 중복 시 숫자 접미사."""
    base = normalize_business_user_id(email)
    if not base:
        base = normalize_business_user_id(username or "user") or "user"
    uid = base
    n = 0
    while User.query.filter_by(user_id=uid).first():
        n += 1
        suffix = str(n)
        max_base = 20 - len(suffix)
        uid = (base[:max_base] if max_base > 0 else "") + suffix
        uid = uid[:20]
    return uid


def allocate_unique_user_id_oauth(provider: str, provider_user_id: str, email: Optional[str]) -> str:
    """OAuth: 이메일 있으면 로컬 파트 우선, 없으면 provider+해시."""
    import hashlib

    if email:
        return allocate_unique_user_id_from_email(email, None)
    h = hashlib.sha256(f"{provider}:{provider_user_id}".encode()).hexdigest()[:18]
    prefix = (provider or "o")[:1]
    uid = f"{prefix}{h}"
    if len(uid) > 20:
        uid = uid[:20]
    n = 0
    orig = uid
    while User.query.filter_by(user_id=uid).first():
        n += 1
        suffix = str(n)
        uid = (orig[: 20 - len(suffix)] + suffix)[:20]
    return uid


def get_user_by_session_value(session_val: Any) -> Optional[User]:
    """Flask 세션의 user_id: 신규는 User.user_id 문자열, 구버전은 정수 PK일 수 있음."""
    if session_val is None:
        return None
    if isinstance(session_val, int):
        return User.query.get(session_val)
    s = str(session_val).strip()
    if not s:
        return None
    if s.isdigit():
        u = User.query.get(int(s))
        if u:
            return u
    return User.query.filter_by(user_id=s).first()


def resolve_user_ref(ref: Any) -> Optional[User]:
    """API의 author_id 등: 정수 PK 또는 업무 user_id 문자열."""
    if ref is None:
        return None
    if isinstance(ref, int):
        return User.query.get(ref)
    s = str(ref).strip()
    if not s:
        return None
    if s.isdigit():
        u = User.query.get(int(s))
        if u:
            return u
    return User.query.filter_by(user_id=s).first()


def get_user_by_business_id(business_id: Any) -> Optional[User]:
    if business_id is None:
        return None
    s = str(business_id).strip()
    if not s:
        return None
    return User.query.filter_by(user_id=s).first()


def parse_mlink_order_user_id(order_id: Optional[str]) -> Optional[str]:
    """
    order_id 예:
    - mlink_<userId>_<8hex>_<amount>_<cycle>_<ts>
    - mlink_usage_<userId>_<8hex>_...
    userId에 '_'가 포함되면 파싱 실패할 수 있음(가정: 업무 user_id는 '_' 미포함).
    """
    if not order_id or not order_id.startswith("mlink_"):
        return None
    if order_id.startswith("mlink_usage_"):
        rest = order_id[len("mlink_usage_") :]
    elif order_id.startswith("mlink_renew_"):
        return None
    else:
        rest = order_id[len("mlink_") :]
    # 다음 토큰은 8자 hex (uuid4 hex[:8])
    m = re.match(r"^(.+?)_([0-9a-fA-F]{8})_", rest)
    if m:
        return m.group(1)
    idx = rest.find("_")
    if idx <= 0:
        return None
    return rest[:idx]
