"""Student feedback on AI-generated content (thumbs up/down).

This closes the AI quality loop started by the human-review workflow (P3.3)
and the versioned prompts (P3.4):

* Every AI-generated artefact (a question, a coach reply, an explanation, a
  translation, ...) can have any number of feedback rows attached to it.
* Feedback is always coupled to a **subject type + subject id** so it can
  point at anything (``encoach.question``, ``encoach.ai.log``, ...) without
  forcing a hard FK per model.
* When the student flags feedback as negative, we also store their free-text
  note so product can triage.

Downstream consumers (prompt library, RAG indexers, report dashboards) can
read ``encoach.ai.feedback`` to compute win rates per prompt key, per model,
per entity, etc.
"""

from __future__ import annotations

from odoo import api, fields, models
from odoo.exceptions import ValidationError


class EncoachAIFeedback(models.Model):
    _name = "encoach.ai.feedback"
    _description = "Student feedback on AI-generated content"
    _order = "create_date desc"
    _rec_name = "subject_key"

    # ------------------------------------------------------------------
    # What was rated
    # ------------------------------------------------------------------
    subject_type = fields.Selection(
        [
            ("question", "Exam question"),
            ("coach", "AI Coach reply"),
            ("explanation", "Content explanation"),
            ("translation", "Translation"),
            ("narrative", "Report narrative"),
            ("other", "Other AI output"),
        ],
        required=True, index=True,
    )
    subject_id = fields.Integer(
        required=True, index=True,
        help="Id of the rated artefact (semantics depend on subject_type).",
    )
    subject_key = fields.Char(
        compute="_compute_subject_key", store=True, index=True,
        help="Denormalised '<type>:<id>' key for quick lookups/aggregations.",
    )

    # Optional link to the AI call that produced this artefact. When set, it
    # lets us correlate feedback with the underlying model/prompt used.
    ai_log_id = fields.Many2one(
        "encoach.ai.log", ondelete="set null", index=True,
    )
    prompt_key = fields.Char(
        index=True,
        help="If the artefact was produced via encoach.ai.prompt, record the "
        "key here so we can compute win-rates per prompt.",
    )
    prompt_version = fields.Integer()

    # ------------------------------------------------------------------
    # Rating
    # ------------------------------------------------------------------
    rating = fields.Selection(
        [("up", "Thumbs up"), ("down", "Thumbs down")],
        required=True, index=True,
    )
    comment = fields.Text(
        help="Free-text note. Required when rating is 'down' and the UI "
        "prompts the student for a reason.",
    )
    tags = fields.Char(
        help="Comma-separated tags (e.g. 'wrong-answer,confusing-stem').",
    )

    # ------------------------------------------------------------------
    # Who / context
    # ------------------------------------------------------------------
    user_id = fields.Many2one(
        "res.users", required=True, index=True,
        default=lambda self: self.env.user,
    )
    entity_id = fields.Many2one(
        "encoach.entity", ondelete="set null", index=True,
    )
    course_id = fields.Many2one(
        "op.course", ondelete="set null", index=True,
    )

    # ------------------------------------------------------------------
    # Triage status (filled in by admins/coaches reviewing feedback).
    # ------------------------------------------------------------------
    status = fields.Selection(
        [
            ("open", "Open"),
            ("acknowledged", "Acknowledged"),
            ("fixed", "Fixed"),
            ("dismissed", "Dismissed"),
        ],
        default="open", index=True,
    )
    resolved_by_id = fields.Many2one(
        "res.users", ondelete="set null",
    )
    resolved_at = fields.Datetime()
    resolution_notes = fields.Text()

    # ------------------------------------------------------------------
    # Constraints
    # ------------------------------------------------------------------
    _sql_constraints = [
        (
            "uniq_user_subject",
            "unique(user_id, subject_type, subject_id)",
            "A user can only leave one feedback row per AI artefact. "
            "Subsequent submissions should update the existing row.",
        ),
    ]

    @api.depends("subject_type", "subject_id")
    def _compute_subject_key(self):
        for rec in self:
            rec.subject_key = f"{rec.subject_type or ''}:{rec.subject_id or 0}"

    @api.constrains("subject_type", "subject_id")
    def _check_subject(self):
        for rec in self:
            if not rec.subject_type or not rec.subject_id:
                raise ValidationError("subject_type and subject_id are required.")
