# backend/app/llm/heuristic.py
import re

from .provider import Classification, LLMProvider

# 시간 표현 → event (요일/시각/날짜)
RE_TIME = re.compile(
    r"(\d{1,2}\s*시|\d{1,2}:\d{2}|오전|오후|"
    r"월요일|화요일|수요일|목요일|금요일|토요일|일요일|"
    r"월요|화요|수요|목요|금요|토요|일요|내일|모레|오늘)"
)
# 행동 동사 + 기한 → task
RE_ACTION = re.compile(r"(사기|구매|하기|맡기기|알아보기|보내기|작성|정리|예약|받|비교|확인|회신|준비)")  # noqa: E501
# work / life 키워드
RE_WORK = re.compile(r"(미팅|회의|리포트|온보딩|OKR|리뷰|배포|스프린트|기획|디자인|개발|보고|발표)")
RE_LIFE = re.compile(r"(가족|여행|선물|구독|병원|생신|자전거|집|수영장|운동|독서|엄마|아빠|티켓)")

WEEKDAY = {"월": "월", "화": "화", "수": "수", "목": "목", "금": "금", "토": "토", "일": "일"}


class HeuristicProvider(LLMProvider):
    name = "heuristic"

    def health(self) -> dict:
        return {
            "reachable": True,
            "provider": "heuristic",
            "model": "rules",
            "detail": "rule-based fallback",
        }

    def generate_json(self, prompt: str, schema: dict | None = None) -> dict:
        return {}  # 폴백 시 scaffold 등은 호출측이 템플릿 사용

    def classify_capture(self, raw: str, context: dict) -> Classification:
        text = raw or ""
        # 1) type: 시간명시 → event, 행동+기한 → task, 막연 → idea
        has_time = bool(RE_TIME.search(text))
        has_clock = bool(re.search(r"(\d{1,2}\s*시|\d{1,2}:\d{2})", text))
        has_action = bool(RE_ACTION.search(text))
        if has_clock:
            ctype = "event"
        elif has_action:
            ctype = "task"
        elif has_time and not has_action:
            ctype = "event"
        else:
            ctype = "idea"

        # 2) sphere
        if RE_WORK.search(text):
            sphere = "work"
        elif RE_LIFE.search(text):
            sphere = "life"
        else:
            sphere = "work"  # 기본 업무

        # 3) project 매칭 (context["projects"]: [{id,name,folder_id}])
        project_id, proj_label, tone = self._match_project(text, sphere, context)

        # 4) due/when/extra/reason
        due_text, when_text = self._time_hints(text, ctype)
        extra = "가격 추적 알림 켜둠" if re.search(r"(티켓|구매|가격)", text) else ""
        reason = self._reason(ctype, sphere, proj_label)

        conf = 0.85 if has_clock or has_action else 0.6
        return Classification(
            type=ctype, sphere=sphere, project_id=project_id, proj_label=proj_label,
            tone=tone, due_text=due_text, when_text=when_text, extra=extra,
            reason=reason, confidence=conf, model="heuristic",
        )

    def _match_project(self, text, sphere, context):
        # 키워드 → 알려진 프로젝트
        rules = [
            (r"(여행|티켓|비행기|한국)", "life-trip", "개인 › 여행 — 한국", "coral"),
            (r"(엄마|아빠|가족|생신|부모)", "life-fam", "가족", "green"),
            (r"(온보딩)", "onb", "온보딩 리디자인 · 아이디어 보드", "violet"),
            (r"(자전거|수리|병원|예약)", None, "개인 캘린더", "blue"),
        ]
        for pat, pid, label, tone in rules:
            if re.search(pat, text):
                return pid, label, tone
        # 없으면 sphere 기본
        if sphere == "life":
            return "me", "개인 › 일상", "blue"
        return None, "업무 › 받은 작업", "ink"

    def _time_hints(self, text, ctype):
        m = re.search(r"(월|화|수|목|금|토|일)요일?\s*(\d{1,2})\s*시", text)
        if m:
            return "", f"{m.group(1)} {int(m.group(2)):02d}:00"
        if "다음 주" in text:
            return "출발 전 · ~6/14", "오늘 21:00 빈 시간 추천"
        return "", ""

    def _reason(self, ctype, sphere, proj_label):
        sph = "업무" if sphere == "work" else "개인"
        if ctype == "event":
            return "시간이 정해진 일은 작업이 아니라 일정으로 바로 등록해요."
        if ctype == "task":
            return (
                f"행동이 있으니 '작업' 맞아요. {sph} 트리의 '{proj_label}'에 넣었어요 — "
                "따로 섹션이 생기는 게 아니라 다른 작업과 똑같이 보여요."
            )
        return "아직 행동이 정해지지 않아 아이디어 보드에 보관했어요."
