"""Heuristic coordinate proposer — a deterministic, rule-based DRAFT seed.

The four curatorial coordinates are a human act (design §11: no automatic ML
coordinate tagging). This proposer only suggests a starting point written as
review_status='proposed'; a human blesses every coordinate before selection.
There is no ML model here — just archive priors (brain plane) and keyword
nudges (mood plane), grounded in the §8 sourcing→axis map.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Protocol

from hef.selection import Coordinate

COORD_MIN, COORD_MAX = 0, 4

# Brain plane (left = verbal/spoken/educational, right = music/wordless/abstract).
_ARCHIVE_PRIORS = {
    "librivox": (4, 0),          # spoken readings
    "internet_archive": (3, 1),  # educational / industrial / Prelinger
    "musopen": (0, 4),           # classical music
    "fma": (0, 4),               # music
    "nasa": (0, 4),              # wordless awe
    "freesound": (0, 4),         # abstract field recordings
}
_ARCHIVE_DEFAULT = (2, 2)

# Mood plane keywords (substring match so "thunderstorm" trips "storm").
_DARK_WORDS = (
    "storm", "night", "noir", "requiem", "minor", "war", "funeral",
    "decay", "death", "grief", "dusk", "winter", "mourning", "shadow",
)
_LIGHT_WORDS = (
    "sunrise", "dawn", "garden", "spring", "joy", "hope", "major",
    "bright", "bloom", "summer", "smile", "light", "morning",
)


def _clamp(v: int) -> int:
    return max(COORD_MIN, min(COORD_MAX, v))


@dataclass
class Signals:
    title: str
    description: str
    source_archive: str
    mode: str
    duration_s: int


@dataclass
class Draft:
    coordinate: Coordinate
    rationale: str


class Proposer(Protocol):
    def propose(self, signals: Signals) -> Draft: ...


class HeuristicProposer:
    def propose(self, signals: Signals) -> Draft:
        left, right = _ARCHIVE_PRIORS.get(
            signals.source_archive, _ARCHIVE_DEFAULT
        )

        text = f"{signals.title} {signals.description}".lower()
        dark_hits = [w for w in _DARK_WORDS if w in text]
        light_hits = [w for w in _LIGHT_WORDS if w in text]
        dark = _clamp(len(dark_hits))
        light = _clamp(len(light_hits))

        coordinate = Coordinate(_clamp(left), _clamp(right), dark, light)

        # Rationale: name the dominant brain prior + any mood keywords.
        brain = (
            f"{signals.source_archive} → "
            + ("strong left" if left >= right else "strong right")
        )
        mood_bits = []
        if dark_hits:
            mood_bits.append(f"{dark_hits[0]!r} → dark")
        if light_hits:
            mood_bits.append(f"{light_hits[0]!r} → light")
        rationale = "; ".join([brain, *mood_bits])

        return Draft(coordinate=coordinate, rationale=rationale)
