from datetime import datetime, timedelta
from enum import StrEnum
from uuid import UUID
from zoneinfo import ZoneInfo

from pydantic import BaseModel, Field, field_serializer


class ClientApiKeyAlgorithm(StrEnum):
    ARGON2 = "ARGON2"  # 旧方式。新規発行では利用しない
    SHA256 = "SHA256"


class ClientApiKeyStatus(StrEnum):
    ACTIVE = "active"
    DEPRECATED = "deprecated"
    EXPIRED = "expired"


class ClientApiKey(BaseModel):
    """クライアントのAPIキー

    クライアント毎に発行する。
    """

    # APIキーのローテーション時に非推奨にしてから有効期限が切れるまでの日数
    ROTATION_DEPRECATION_DAYS: int = 7

    id: str
    client_id: UUID
    algorithm: ClientApiKeyAlgorithm
    hashed_secret: str
    status: ClientApiKeyStatus = Field(default=ClientApiKeyStatus.ACTIVE)
    rotated_at: datetime | None = Field(default=None)
    expires_at: datetime | None = Field(default=None)

    @field_serializer("rotated_at", "expires_at")
    def serialize_datetime(self, value: datetime | None) -> str | None:
        return value.strftime("%Y-%m-%d %H:%M:%S.%f") if value else None

    def mark_as_rotated(self) -> "ClientApiKey":
        """APIキーをローテーション済みにする

        非推奨キーとなり、数日後に有効期限が切れるように設定する
        """
        now = datetime.now(tz=ZoneInfo("Asia/Tokyo"))
        return self.model_copy(
            update={
                "status": ClientApiKeyStatus.DEPRECATED,
                "rotated_at": now,
                "expires_at": now + timedelta(days=self.ROTATION_DEPRECATION_DAYS),
            },
        )
