from __future__ import annotations

from dataclasses import dataclass
from datetime import UTC, datetime, timedelta
from re import fullmatch

from fastapi import HTTPException, status

from app.core.config import get_settings


@dataclass
class SmsCodeRecord:
    code: str
    expires_at: datetime


class SmsCodeService:
    _codes: dict[str, SmsCodeRecord] = {}

    @classmethod
    def send_code(cls, phone: str) -> None:
        cls._validate_phone(phone)
        settings = get_settings()
        if not settings.mock_sms_enabled:
            raise HTTPException(status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="真实短信服务尚未接入")
        cls._codes[phone] = SmsCodeRecord(
            code=settings.mock_sms_code,
            expires_at=datetime.now(UTC) + timedelta(minutes=settings.sms_code_expire_minutes),
        )

    @classmethod
    def verify_code(cls, phone: str, code: str) -> None:
        cls._validate_phone(phone)
        record = cls._codes.get(phone)
        settings = get_settings()
        if settings.mock_sms_enabled and record is None and code == settings.mock_sms_code:
            return
        if record is None:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="验证码不存在或已过期")
        if record.expires_at < datetime.now(UTC):
            cls._codes.pop(phone, None)
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="验证码已过期")
        if record.code != code:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="验证码错误")
        cls._codes.pop(phone, None)

    @staticmethod
    def _validate_phone(phone: str) -> None:
        if fullmatch(r"1[3-9]\d{9}", phone) is None:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="手机号格式不正确")
