# backend/app/llm/ollama.py
import json

import httpx

from ..config import get_settings
from .heuristic import HeuristicProvider
from .prompts import CLASSIFY_SYSTEM, build_classify_prompt
from .provider import Classification, LLMProvider


class OllamaProvider(LLMProvider):
    name = "ollama"

    def __init__(self):
        st = get_settings()
        self.host = st.ollama_host
        self.model = st.ollama_model  # 비종속: env 주입값 그대로 사용
        self.timeout = st.llm_timeout

    def health(self) -> dict:
        try:
            r = httpx.get(f"{self.host}/api/tags", timeout=3.0)
            ok = r.status_code == 200
            tags = [m.get("name") for m in r.json().get("models", [])] if ok else []
            return {
                "reachable": ok, "provider": "ollama", "model": self.model,
                "host": self.host, "detail": f"models={tags}",
            }
        except Exception as e:
            return {
                "reachable": False, "provider": "ollama", "model": self.model,
                "host": self.host, "detail": str(e),
            }

    def generate_json(self, prompt: str, schema: dict | None = None) -> dict:
        # Ollama 구조화 출력: format="json" (모델 비종속). chat API 사용.
        # think=False: 추론형 모델의 사고 단계를 끈다(분류는 즉답이 더 적합·빠름).
        # 미지원 모델은 무시되거나, 거부 시 except 에서 폴백 처리.
        payload = {
            "model": self.model,
            "messages": [{"role": "user", "content": prompt}],
            "stream": False,
            "format": "json",
            "think": False,
            "options": {"temperature": 0.2},
        }
        r = httpx.post(f"{self.host}/api/chat", json=payload, timeout=self.timeout)
        r.raise_for_status()
        content = r.json()["message"]["content"]
        return json.loads(content)

    def classify_capture(self, raw: str, context: dict) -> Classification:
        prompt = build_classify_prompt(raw, context)
        try:
            payload = {
                "model": self.model,
                "messages": [
                    {"role": "system", "content": CLASSIFY_SYSTEM},
                    {"role": "user", "content": prompt},
                ],
                "stream": False,
                "format": "json",
                "think": False,  # 추론 단계 off → 분류 즉답(수초). 미지원 시 except 폴백.
                "options": {"temperature": 0.2},
            }
            r = httpx.post(f"{self.host}/api/chat", json=payload, timeout=self.timeout)
            r.raise_for_status()
            data = json.loads(r.json()["message"]["content"])
            return _coerce(data, raw, context, model=f"ollama:{self.model}")
        except Exception:
            # 모델 미가용/파싱 실패 → 규칙 폴백 (오프라인에서도 동작)
            return HeuristicProvider().classify_capture(raw, context)


def _coerce(data: dict, raw: str, context: dict, model: str) -> Classification:
    """LLM JSON을 Classification으로. 누락 필드는 휴리스틱/기본값 보강."""
    h = HeuristicProvider().classify_capture(raw, context)  # 폴백 베이스
    t = data.get("type") if data.get("type") in ("task", "event", "idea") else h.type
    sp = data.get("sphere") if data.get("sphere") in ("work", "life") else h.sphere
    return Classification(
        type=t, sphere=sp,
        project_id=data.get("project_id") or h.project_id,
        proj_label=data.get("proj_label") or h.proj_label,
        tone=data.get("tone") or h.tone,
        due_text=data.get("due_text", h.due_text),
        when_text=data.get("when_text", h.when_text),
        extra=data.get("extra", h.extra),
        reason=data.get("reason") or h.reason,
        confidence=float(data.get("confidence", 0.85)),
        model=model,
    )
