from typing import Optional

import httpx
from pydantic import BaseModel
from sqlmodel import Field, Relationship, SQLModel

from learn_sql_model.config import config
from learn_sql_model.models.pet import Pet


class {{ model.lower }}Base(SQLModel, table=False):
    name: str
    secret_name: str
    x: int
    y: int
    size: int
    age: Optional[int] = None
    shoe_size: Optional[int] = None

    pet_id: Optional[int] = Field(default=None, foreign_key="pet.id")
    pet: Optional[Pet] = Relationship(back_populates="{{ model.lower() }}")


class {{ model.lower }}({{ model.lower }}Base, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)


class {{ model.lower }}Create({{ model.lower }}Base):
    ...

    def post(self) -> {{ model.lower }}:
        r = httpx.post(
            f"{config.api_client.url}/{{ model.lower() }}/",
            json=self.dict(),
        )
        if r.status_code != 200:
            raise RuntimeError(f"{r.status_code}:\n {r.text}")

        return {{ model.lower }}.parse_obj(r.json())


class {{ model.lower }}Read({{ model.lower }}Base):
    id: int

    @classmethod
    def get(
        cls,
        id: int,
    ) -> {{ model.lower }}:
        r = httpx.get(f"{config.api_client.url}/{{ model.lower() }}/{id}")
        if r.status_code != 200:
            raise RuntimeError(f"{r.status_code}:\n {r.text}")
        return {{ model.lower() }}


class {{ model.lower }}s(BaseModel):
    {{ model.lower() }}s: list[{{ model.lower }}]

    @classmethod
    def list(
        self,
    ) -> {{ model.lower }}:
        r = httpx.get(f"{config.api_client.url}/{{ model.lower() }}s/")
        if r.status_code != 200:
            raise RuntimeError(f"{r.status_code}:\n {r.text}")
        return {{ model.lower }}s.parse_obj(r.json())


class {{ model.lower }}Update(SQLModel):
    # id is required to update the {{ model.lower() }}
    id: int

    # all other fields, must match the model, but with Optional default None
    name: Optional[str] = None
    secret_name: Optional[str] = None
    age: Optional[int] = None
    shoe_size: Optional[int] = None
    x: int
    y: int

    pet_id: Optional[int] = Field(default=None, foreign_key="pet.id")
    pet: Optional[Pet] = Relationship(back_populates="{{ model.lower() }}")

    def update(self) -> {{ model.lower }}:
        r = httpx.patch(
            f"{config.api_client.url}/{{ model.lower() }}/",
            json=self.dict(),
        )
        if r.status_code != 200:
            raise RuntimeError(f"{r.status_code}:\n {r.text}")


class {{ model.lower }}Delete(BaseModel):
    id: int

    def delete(self) -> {{ model.lower }}:
        r = httpx.delete(
            f"{config.api_client.url}/{{ model.lower() }}/{self.id}",
        )
        if r.status_code != 200:
            raise RuntimeError(f"{r.status_code}:\n {r.text}")
        return {"ok": True}

