"""Endpoints for submitting & aggregating AI feedback."""

import logging

from odoo import fields, http
from odoo.http import request

from odoo.addons.encoach_api.controllers.base import (
    _error_response,
    _get_json_body,
    _json_response,
    _paginate,
    jwt_required,
)

_logger = logging.getLogger(__name__)


def _feedback_to_dict(row):
    return {
        "id": row.id,
        "subject_type": row.subject_type,
        "subject_id": row.subject_id,
        "subject_key": row.subject_key,
        "rating": row.rating,
        "comment": row.comment or "",
        "tags": (row.tags or "").split(",") if row.tags else [],
        "prompt_key": row.prompt_key or None,
        "prompt_version": row.prompt_version or None,
        "ai_log_id": row.ai_log_id.id if row.ai_log_id else None,
        "user_id": row.user_id.id,
        "user_name": row.user_id.name,
        "entity_id": row.entity_id.id if row.entity_id else None,
        "course_id": row.course_id.id if row.course_id else None,
        "status": row.status,
        "create_date": (
            fields.Datetime.to_string(row.create_date) if row.create_date else None
        ),
        "resolved_at": (
            fields.Datetime.to_string(row.resolved_at) if row.resolved_at else None
        ),
        "resolution_notes": row.resolution_notes or "",
    }


class EncoachAIFeedbackController(http.Controller):
    """Feedback write + admin triage endpoints."""

    # ------------------------------------------------------------------
    # POST /api/ai/feedback — student submits/updates feedback
    #
    # Upsert semantics: we enforce uniqueness per (user, subject_type,
    # subject_id) at the DB layer, so the client doesn't need to know whether
    # the row already exists.
    # ------------------------------------------------------------------
    @http.route("/api/ai/feedback", type="http", auth="none", methods=["POST"], csrf=False)
    @jwt_required
    def submit(self, **kw):
        try:
            body = _get_json_body() or {}
            subject_type = body.get("subject_type")
            subject_id = body.get("subject_id")
            rating = body.get("rating")
            if subject_type not in {
                "question", "coach", "explanation", "translation", "narrative", "other",
            }:
                return _error_response("Invalid subject_type", 400)
            if not isinstance(subject_id, int) or subject_id <= 0:
                return _error_response("subject_id must be a positive integer", 400)
            if rating not in {"up", "down"}:
                return _error_response("rating must be 'up' or 'down'", 400)
            comment = body.get("comment") or ""
            if rating == "down" and not (comment or "").strip():
                # We keep this a soft constraint so the UI can decide how
                # strict to be; returning an error here gives clients a clear
                # path to prompt the user when needed.
                return _error_response(
                    "A short comment is required when rating is 'down'.", 400,
                )

            vals = {
                "subject_type": subject_type,
                "subject_id": subject_id,
                "rating": rating,
                "comment": comment,
                "tags": (
                    ",".join(body.get("tags") or [])
                    if isinstance(body.get("tags"), list)
                    else (body.get("tags") or "")
                ),
                "prompt_key": body.get("prompt_key") or False,
                "prompt_version": body.get("prompt_version") or 0,
                "ai_log_id": body.get("ai_log_id") or False,
                "entity_id": body.get("entity_id") or False,
                "course_id": body.get("course_id") or False,
                "user_id": request.env.user.id,
            }

            Feedback = request.env["encoach.ai.feedback"].sudo()
            existing = Feedback.search([
                ("user_id", "=", request.env.user.id),
                ("subject_type", "=", subject_type),
                ("subject_id", "=", subject_id),
            ], limit=1)
            with request.env.cr.savepoint():
                if existing:
                    existing.write(vals)
                    row = existing
                else:
                    row = Feedback.create(vals)
            return _json_response(_feedback_to_dict(row), 200 if existing else 201)
        except Exception as e:
            _logger.exception("ai feedback submit failed")
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # GET /api/ai/feedback/summary?subject_type=question&subject_id=42
    # ------------------------------------------------------------------
    @http.route(
        "/api/ai/feedback/summary", type="http", auth="none", methods=["GET"], csrf=False,
    )
    @jwt_required
    def summary(self, subject_type=None, subject_id=None, **kw):
        try:
            if not subject_type or not subject_id:
                return _error_response("subject_type and subject_id are required", 400)
            Feedback = request.env["encoach.ai.feedback"].sudo()
            domain = [
                ("subject_type", "=", subject_type),
                ("subject_id", "=", int(subject_id)),
            ]
            rows = Feedback.search(domain)
            up = sum(1 for r in rows if r.rating == "up")
            down = sum(1 for r in rows if r.rating == "down")
            my_row = Feedback.search([
                *domain,
                ("user_id", "=", request.env.user.id),
            ], limit=1)
            return _json_response({
                "subject_type": subject_type,
                "subject_id": int(subject_id),
                "up": up,
                "down": down,
                "total": up + down,
                "my_rating": my_row.rating if my_row else None,
                "my_comment": my_row.comment or "" if my_row else "",
            })
        except Exception as e:
            _logger.exception("ai feedback summary failed")
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # GET /api/ai/feedback — admin triage list
    # ------------------------------------------------------------------
    @http.route("/api/ai/feedback", type="http", auth="none", methods=["GET"], csrf=False)
    @jwt_required
    def list_feedback(self, **kw):
        try:
            if not request.env.user.has_group("base.group_system"):
                return _error_response("Admin privileges required", 403)
            Feedback = request.env["encoach.ai.feedback"].sudo()
            domain = []
            if kw.get("status"):
                domain.append(("status", "=", kw["status"]))
            if kw.get("rating"):
                domain.append(("rating", "=", kw["rating"]))
            if kw.get("subject_type"):
                domain.append(("subject_type", "=", kw["subject_type"]))
            if kw.get("prompt_key"):
                domain.append(("prompt_key", "=", kw["prompt_key"]))
            offset, limit, page = _paginate(kw)
            total = Feedback.search_count(domain)
            rows = Feedback.search(domain, offset=offset, limit=limit, order="create_date desc")
            items = [_feedback_to_dict(r) for r in rows]
            return _json_response({
                "items": items,
                "data": items,
                "total": total,
                "page": page,
                "size": limit,
            })
        except Exception as e:
            _logger.exception("ai feedback list failed")
            return _error_response(str(e), 500)

    # ------------------------------------------------------------------
    # POST /api/ai/feedback/<id>/resolve — admin triage
    # ------------------------------------------------------------------
    @http.route(
        '/api/ai/feedback/<int:feedback_id>/resolve',
        type="http", auth="none", methods=["POST"], csrf=False,
    )
    @jwt_required
    def resolve(self, feedback_id, **kw):
        try:
            if not request.env.user.has_group("base.group_system"):
                return _error_response("Admin privileges required", 403)
            body = _get_json_body() or {}
            status = body.get("status")
            if status not in {"acknowledged", "fixed", "dismissed"}:
                return _error_response(
                    "status must be one of acknowledged|fixed|dismissed", 400,
                )
            row = request.env["encoach.ai.feedback"].sudo().browse(feedback_id)
            if not row.exists():
                return _error_response("Feedback not found", 404)
            with request.env.cr.savepoint():
                row.write({
                    "status": status,
                    "resolved_by_id": request.env.user.id,
                    "resolved_at": fields.Datetime.now(),
                    "resolution_notes": body.get("notes") or "",
                })
            return _json_response(_feedback_to_dict(row))
        except Exception as e:
            _logger.exception("ai feedback resolve failed")
            return _error_response(str(e), 500)
