import uuid
from typing import Optional, Dict, Any
from pydantic import EmailStr, BaseModel
from sqlmodel import Field, Relationship, SQLModel
from datetime import datetime
from sqlalchemy import JSON


# Shared properties
class UserBase(SQLModel):
    email: EmailStr = Field(unique=True, index=True, max_length=255)
    is_active: bool = True
    is_superuser: bool = False
    full_name: str | None = Field(default=None, max_length=255)


# Properties to receive via API on creation
class UserCreate(UserBase):
    password: str = Field(min_length=8, max_length=40)


class UserRegister(SQLModel):
    email: EmailStr = Field(max_length=255)
    password: str = Field(min_length=8, max_length=40)
    full_name: str | None = Field(default=None, max_length=255)


# Properties to receive via API on update, all are optional
class UserUpdate(UserBase):
    email: EmailStr | None = Field(default=None, max_length=255)  # type: ignore
    password: str | None = Field(default=None, min_length=8, max_length=40)


class UserUpdateMe(SQLModel):
    full_name: str | None = Field(default=None, max_length=255)
    email: EmailStr | None = Field(default=None, max_length=255)


class UpdatePassword(SQLModel):
    current_password: str = Field(min_length=8, max_length=40)
    new_password: str = Field(min_length=8, max_length=40)


# Database model, database table inferred from class name
class User(UserBase, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
    hashed_password: str
    items: list["Item"] = Relationship(back_populates="owner", cascade_delete=True)


# Properties to return via API, id is always required
class UserPublic(UserBase):
    id: uuid.UUID


class UsersPublic(SQLModel):
    data: list[UserPublic]
    count: int


# Shared properties
class ItemBase(SQLModel):
    title: str = Field(min_length=1, max_length=255)
    description: str | None = Field(default=None, max_length=255)


# Properties to receive on item creation
class ItemCreate(ItemBase):
    pass


# Properties to receive on item update
class ItemUpdate(ItemBase):
    title: str | None = Field(default=None, min_length=1, max_length=255)  # type: ignore


# Database model, database table inferred from class name
class Item(ItemBase, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
    title: str = Field(max_length=255)
    owner_id: uuid.UUID = Field(
        foreign_key="user.id", nullable=False, ondelete="CASCADE"
    )
    owner: User | None = Relationship(back_populates="items")


# Properties to return via API, id is always required
class ItemPublic(ItemBase):
    id: uuid.UUID
    owner_id: uuid.UUID


class ItemsPublic(SQLModel):
    data: list[ItemPublic]
    count: int


# Generic message
class Message(SQLModel):
    message: str


# JSON payload containing access token
class Token(SQLModel):
    access_token: str
    token_type: str = "bearer"


# Contents of JWT token
class TokenPayload(SQLModel):
    sub: str | None = None


class NewPassword(SQLModel):
    token: str
    new_password: str = Field(min_length=8, max_length=40)


# Client Messages


class MessageBase(SQLModel):
    name: str = Field(max_length=255)
    phone: str = Field(max_length=255)
    email: str = Field(max_length=255)
    message: str = Field(max_length=1024)


class Message(MessageBase, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
    created_at: datetime = Field(default_factory=datetime.utcnow)


class MessageCreate(MessageBase):
    pass


class MessagePublic(MessageBase):
    id: uuid.UUID


class MessagesPublic(SQLModel):
    data: list[Message]
    count: int


# setting


class SettingBase(SQLModel):
    address: str = Field(max_length=255)
    google_map_api_key: str = Field(max_length=255)
    latitude: float
    longitude: float
    phone: str = Field(max_length=255)
    email: str = Field(max_length=255)
    facebook: str = Field(max_length=255)
    instagram: str = Field(max_length=255)
    youtube: str = Field(max_length=255)
    youtube_link: str = Field(max_length=255)
    whatsapp: str = Field(max_length=255)


class SettingCreate(SettingBase):
    pass


class Setting(SettingBase, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)


# organ
class OrganBase(SQLModel):
    description: str = Field(max_length=1024)
    image: str | None = Field(default=None, max_length=255)
    title: str = Field(max_length=255)
    index: int


class OrganCreate(OrganBase):
    pass


class Organ(OrganBase, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)


class OrganPublic(OrganBase):
    id: uuid.UUID


class OrganUpdate(OrganBase):
    pass


class OrganListPublic(SQLModel):
    data: list[OrganPublic]
    count: int


# About us


class AboutUsBase(SQLModel):
    description: str = Field(max_length=1024)
    image: str | None = Field(default=None, max_length=255)
    title: str = Field(max_length=255)
    index: int


class AboutUsCreate(AboutUsBase):
    pass


class AboutUs(AboutUsBase, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)


class AboutUsPublic(AboutUsBase):
    id: uuid.UUID


class AboutsUpdate(AboutUsBase):
    pass


class AboutsListPublic(SQLModel):
    data: list[AboutUsPublic]
    count: int


# courses


class CourseBase(SQLModel):
    title: str = Field(max_length=255)
    sort_description: str = Field(max_length=32768)
    long_description: str = Field(max_length=32768)
    information: str = Field(max_length=32768)
    contant: str = Field(max_length=32768)
    remark: str = Field(max_length=32768)


class CourseCreate(CourseBase):
    pass


class CourseUpdate(CourseBase):
    pass


class Course(CourseBase, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
    created_at: datetime = Field(default_factory=datetime.utcnow)
    images: list["Image"] = Relationship(back_populates="course", cascade_delete=True)
    info_images: list["Info_Image"] = Relationship(
        back_populates="course", cascade_delete=True
    )
    schedule: list["Schedule"] = Relationship(
        back_populates="course", cascade_delete=True
    )


class CoursePublic(CourseBase):
    id: uuid.UUID
    title: str
    images: list["Image"]
    info_images: list["Info_Image"]
    schedule: list["Schedule"]
    created_at: datetime


class CoursesPublic(SQLModel):
    data: list[CoursePublic]
    count: int


# Image
class ImageBase(SQLModel):
    image: str = Field(max_length=255)
    index: int


class ImagePublic(ImageBase):
    id: uuid.UUID


class ImageCreate(ImageBase):
    course_id: uuid.UUID


class Image(ImageBase, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
    course_id: uuid.UUID = Field(
        foreign_key="course.id", nullable=False, ondelete="CASCADE"
    )
    course: Course | None = Relationship(back_populates="images")


class Info_ImageBase(SQLModel):
    image: str = Field(max_length=255)
    index: int


class Info_ImageCreate(Info_ImageBase):
    course_id: uuid.UUID


class Info_Image(Info_ImageBase, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
    course_id: uuid.UUID = Field(
        foreign_key="course.id", nullable=False, ondelete="CASCADE"
    )
    course: Course | None = Relationship(back_populates="info_images")


# schedules
class ScheduleBase(SQLModel):
    title: str = Field(max_length=255)
    info1: str = Field(max_length=255)
    info2: str = Field(max_length=255)
    date: str


class ScheduleUpdate(ScheduleBase):
    pass


class ScheduleCreate(ScheduleBase):
    course_id: uuid.UUID


class Schedule(ScheduleBase, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
    course_id: uuid.UUID = Field(
        foreign_key="course.id", nullable=False, ondelete="CASCADE"
    )
    course: Course | None = Relationship(back_populates="schedule")


class CoursePublicWithImages(CoursePublic):
    images: list[Image] = []
    info_images: list[Info_Image] = []
    schedule: list[Schedule] = []
