from datetime import datetime
from typing import Literal
from uuid import UUID

from pydantic import BaseModel, ConfigDict, Field, model_validator


BusinessRole = Literal["admin", "user", "operator", "viewer"]
ProjectRole = Literal["owner", "admin", "member", "viewer"]
ProjectStatus = Literal["active", "inactive", "archived"]
ProjectDbRole = Literal["biz_data", "iot_data"]


class MetadataUserSyncRequest(BaseModel):
    keycloak_id: UUID
    username: str = Field(..., min_length=1, max_length=50)
    email: str = Field(..., min_length=1, max_length=100)
    role: BusinessRole = "user"
    is_active: bool = True


class MetadataUsersBatchSyncRequest(BaseModel):
    users: list[MetadataUserSyncRequest] = Field(..., min_length=1, max_length=500)


class MetadataUserUpdateRequest(BaseModel):
    role: BusinessRole | None = None
    is_active: bool | None = None


class MetadataUserResponse(BaseModel):
    id: UUID
    keycloak_id: UUID
    username: str
    email: str
    role: str
    is_active: bool
    is_superuser: bool
    created_at: datetime
    updated_at: datetime
    last_login_at: datetime | None = None

    model_config = ConfigDict(from_attributes=True)


class MetadataUserSyncResult(BaseModel):
    keycloak_id: UUID
    user: MetadataUserResponse | None = None
    success: bool
    error: str | None = None


class ProjectMemberCreateRequest(BaseModel):
    user_id: UUID
    project_role: ProjectRole = "viewer"


class ProjectMemberUpdateRequest(BaseModel):
    project_role: ProjectRole


class ProjectMemberResponse(BaseModel):
    id: UUID
    user_id: UUID
    project_id: UUID
    project_role: str
    username: str
    email: str
    is_active: bool


class AdminProjectCreateRequest(BaseModel):
    name: str = Field(..., min_length=1, max_length=100)
    code: str = Field(..., min_length=1, max_length=50)
    description: str | None = None
    gs_workspace: str = Field(..., min_length=1, max_length=100)
    map_extent: dict | None = None
    status: ProjectStatus = "active"


class AdminProjectUpdateRequest(BaseModel):
    name: str | None = Field(default=None, min_length=1, max_length=100)
    code: str | None = Field(default=None, min_length=1, max_length=50)
    description: str | None = None
    gs_workspace: str | None = Field(default=None, min_length=1, max_length=100)
    map_extent: dict | None = None
    status: ProjectStatus | None = None


class AdminProjectResponse(BaseModel):
    project_id: UUID
    name: str
    code: str
    description: str | None = None
    gs_workspace: str
    map_extent: dict | None = None
    status: str
    created_at: datetime
    updated_at: datetime


class ProjectDatabaseUpsertRequest(BaseModel):
    db_role: ProjectDbRole
    dsn: str | None = Field(default=None, min_length=1)
    pool_min_size: int = Field(default=2, ge=1)
    pool_max_size: int = Field(default=10, ge=1)

    @model_validator(mode="after")
    def validate_pool_bounds(self):
        if self.pool_max_size < self.pool_min_size:
            raise ValueError("pool_max_size must be greater than or equal to pool_min_size")
        return self


class ProjectDatabaseResponse(BaseModel):
    id: UUID
    project_id: UUID
    db_role: str
    db_type: str
    pool_min_size: int
    pool_max_size: int
    has_dsn: bool


class ProjectDatabaseHealthRequest(BaseModel):
    dsn: str | None = Field(default=None, min_length=1)


class ProjectDatabaseHealthResponse(BaseModel):
    project_id: UUID
    db_role: str
    db_type: str
    ok: bool
    detail: str
