import time

from asgiref.sync import sync_to_async
from django.utils import timezone
from openai import AsyncOpenAI

from core.models import AI, AIRunLog


def _prompt_metrics(prompt: list[dict]) -> tuple[int, int]:
    rows = list(prompt or [])
    message_count = len(rows)
    prompt_chars = 0
    for row in rows:
        content = ""
        if isinstance(row, dict):
            content = str(row.get("content") or "")
        else:
            content = str(row or "")
        prompt_chars += len(content)
    return message_count, prompt_chars


async def run_prompt(
    prompt: list[dict],
    ai: AI,
    operation: str = "",
):
    started_monotonic = time.perf_counter()
    message_count, prompt_chars = _prompt_metrics(prompt)
    run_log = await sync_to_async(AIRunLog.objects.create)(
        user=ai.user,
        ai=ai,
        operation=str(operation or "").strip(),
        model=str(ai.model or ""),
        base_url=str(ai.base_url or ""),
        status="running",
        message_count=message_count,
        prompt_chars=prompt_chars,
    )
    cast = {"api_key": ai.api_key}
    if ai.base_url is not None:
        cast["base_url"] = ai.base_url
    client = AsyncOpenAI(**cast)
    try:
        response = await client.chat.completions.create(
            model=ai.model,
            messages=prompt,
        )
        content = response.choices[0].message.content
        duration_ms = int((time.perf_counter() - started_monotonic) * 1000)
        await sync_to_async(AIRunLog.objects.filter(id=run_log.id).update)(
            status="ok",
            response_chars=len(str(content or "")),
            finished_at=timezone.now(),
            duration_ms=duration_ms,
            error="",
        )
        return content
    except Exception as exc:
        duration_ms = int((time.perf_counter() - started_monotonic) * 1000)
        await sync_to_async(AIRunLog.objects.filter(id=run_log.id).update)(
            status="failed",
            finished_at=timezone.now(),
            duration_ms=duration_ms,
            error=str(exc),
        )
        raise
