"""{{ project_name }} -- FastAPI server powered by Prompture."""

from __future__ import annotations

import json
import uuid
from typing import Any

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware

from .config import settings
from .models import (
    ChatRequest,
    ChatResponse,
    ConversationHistory,
    ExtractRequest,
    ExtractResponse,
)

from prompture import AsyncConversation

app = FastAPI(title="{{ project_name }}", version="0.1.0")

app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.cors_origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

_conversations: dict[str, AsyncConversation] = {}


def _get_or_create_conversation(conv_id: str | None) -> tuple[str, AsyncConversation]:
    if conv_id and conv_id in _conversations:
        return conv_id, _conversations[conv_id]
    new_id = conv_id or uuid.uuid4().hex[:12]
    conv = AsyncConversation(
        model_name=settings.model_name,
        system_prompt=settings.system_prompt,
    )
    _conversations[new_id] = conv
    return new_id, conv


@app.post("/v1/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    conv_id, conv = _get_or_create_conversation(request.conversation_id)
    text = await conv.ask(request.message, request.options)
    return ChatResponse(message=text, conversation_id=conv_id, usage=conv.usage)


@app.post("/v1/extract", response_model=ExtractResponse)
async def extract(request: ExtractRequest):
    conv_id, conv = _get_or_create_conversation(request.conversation_id)
    result = await conv.ask_for_json(
        content=request.text,
        json_schema=request.schema_def,
    )
    return ExtractResponse(
        json_object=result["json_object"],
        conversation_id=conv_id,
        usage=conv.usage,
    )


@app.get("/v1/conversations/{conversation_id}", response_model=ConversationHistory)
async def get_conversation(conversation_id: str):
    if conversation_id not in _conversations:
        raise HTTPException(status_code=404, detail="Conversation not found")
    conv = _conversations[conversation_id]
    return ConversationHistory(
        conversation_id=conversation_id,
        messages=conv.messages,
        usage=conv.usage,
    )


@app.delete("/v1/conversations/{conversation_id}")
async def delete_conversation(conversation_id: str):
    if conversation_id not in _conversations:
        raise HTTPException(status_code=404, detail="Conversation not found")
    del _conversations[conversation_id]
    return {"status": "deleted", "conversation_id": conversation_id}
