using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using UniVerse.Application.DTOs.Common;
using UniVerse.Application.DTOs.Reviews;
using UniVerse.Application.Interfaces;
using System.Security.Claims;

namespace UniVerse.Api.Controllers;

/// <summary>Отзывы студентов на лекции с LLM-анализом и модерацией.</summary>
[ApiController]
[Route("api/v1/reviews")]
[Authorize]
[Produces("application/json")]
public class ReviewsController : ControllerBase
{
    private readonly IReviewService _reviews;
    private readonly IReviewPromptService _reviewPrompts;

    public ReviewsController(IReviewService reviews, IReviewPromptService reviewPrompts)
    {
        _reviews = reviews;
        _reviewPrompts = reviewPrompts;
    }

    private int CurrentUserId => int.Parse(
        User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub") ?? "0");

    /// <summary>Создать отзыв к лекции.</summary>
    /// <remarks>
    /// Только Student. После создания отзыв отправляется на LLM-анализ
    /// (статус `Pending`). LLM оценивает содержательность и начисляет монеты
    /// скрытно от пользователя.
    /// </remarks>
    /// <param name="req">ID лекции, оценка (Like/Neutral/Dislike) и текст отзыва.</param>
    /// <response code="201">Отзыв создан и поставлен в очередь на LLM-анализ.</response>
    /// <response code="401">Требуется аутентификация.</response>
    /// <response code="403">Требуется роль Student.</response>
    /// <response code="404">Лекция не найдена.</response>
    /// <response code="409">Студент уже оставил отзыв к этой лекции.</response>
    [Authorize(Roles = "Student")]
    [HttpPost]
    [ProducesResponseType(typeof(ReviewDto), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<ActionResult<ReviewDto>> Create([FromBody] CreateReviewRequest req) =>
        CreatedAtAction(nameof(Get), new { id = 0 }, await _reviews.CreateAsync(CurrentUserId, req));

    /// <summary>Получить список всех отзывов.</summary>
    /// <remarks>Только Admin. Возвращает все отзывы независимо от LLM-статуса.</remarks>
    /// <param name="filter">Параметры фильтрации и пагинации.</param>
    /// <response code="200">Список всех отзывов (пагинированный).</response>
    /// <response code="401">Требуется аутентификация.</response>
    /// <response code="403">Требуется роль Admin.</response>
    [Authorize(Roles = "Admin")]
    [HttpGet]
    [ProducesResponseType(typeof(PagedResult<ReviewDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    public async Task<ActionResult> List([FromQuery] ReviewFilterRequest filter) =>
        Ok(await _reviews.GetAllAsync(filter));

    /// <summary>Получить текущий промпт LLM-анализа отзывов.</summary>
    /// <remarks>Только Admin. Если настройка ещё не сохранена, возвращает базовый промпт.</remarks>
    /// <response code="200">Текущий шаблон промпта.</response>
    /// <response code="401">Требуется аутентификация.</response>
    /// <response code="403">Требуется роль Admin.</response>
    [Authorize(Roles = "Admin")]
    [HttpGet("llm-prompt")]
    [ProducesResponseType(typeof(ReviewPromptDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    public async Task<ActionResult<ReviewPromptDto>> GetLlmPrompt() =>
        Ok(await _reviewPrompts.GetAsync());

    /// <summary>Обновить промпт LLM-анализа отзывов.</summary>
    /// <remarks>Только Admin. Промпт применяется к следующим анализам и ручным повторам.</remarks>
    /// <param name="request">Новый шаблон с плейсхолдерами {lectureContext} и {reviewText}.</param>
    /// <response code="200">Сохранённый шаблон промпта.</response>
    /// <response code="400">Промпт пустой или не содержит обязательные плейсхолдеры.</response>
    /// <response code="401">Требуется аутентификация.</response>
    /// <response code="403">Требуется роль Admin.</response>
    [Authorize(Roles = "Admin")]
    [HttpPut("llm-prompt")]
    [ProducesResponseType(typeof(ReviewPromptDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    public async Task<ActionResult<ReviewPromptDto>> UpdateLlmPrompt([FromBody] UpdateReviewPromptRequest request) =>
        Ok(await _reviewPrompts.UpdateAsync(request));

    /// <summary>Получить отзыв по ID.</summary>
    /// <remarks>Только Admin или Teacher.</remarks>
    /// <param name="id">ID отзыва.</param>
    /// <response code="200">Данные отзыва (включая LLM-статус и сентимент).</response>
    /// <response code="401">Требуется аутентификация.</response>
    /// <response code="403">Требуется роль Admin или Teacher.</response>
    /// <response code="404">Отзыв не найден.</response>
    [Authorize(Roles = "Admin,Teacher")]
    [HttpGet("{id:int}")]
    [ProducesResponseType(typeof(ReviewDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<ReviewDto>> Get(int id) => Ok(await _reviews.GetByIdAsync(id));

    /// <summary>Обновить отзыв.</summary>
    /// <remarks>
    /// Разрешено любому авторизованному пользователю, но сервис проверяет владельца.
    /// Изменение текста сбрасывает LLM-статус в `Pending` (повторный анализ).
    /// </remarks>
    /// <param name="id">ID отзыва.</param>
    /// <param name="req">Новая оценка и/или текст.</param>
    /// <response code="200">Обновлённые данные отзыва.</response>
    /// <response code="401">Требуется аутентификация.</response>
    /// <response code="403">Отзыв принадлежит другому пользователю.</response>
    /// <response code="404">Отзыв не найден.</response>
    [HttpPut("{id:int}")]
    [ProducesResponseType(typeof(ReviewDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<ReviewDto>> Update(int id, [FromBody] UpdateReviewRequest req) =>
        Ok(await _reviews.UpdateAsync(id, CurrentUserId, req));

    /// <summary>Удалить отзыв.</summary>
    /// <remarks>Владелец может удалить свой отзыв. Admin может удалить любой.</remarks>
    /// <param name="id">ID отзыва.</param>
    /// <response code="204">Отзыв удалён.</response>
    /// <response code="401">Требуется аутентификация.</response>
    /// <response code="403">Нет прав на удаление (не владелец и не Admin).</response>
    /// <response code="404">Отзыв не найден.</response>
    [HttpDelete("{id:int}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> Delete(int id)
    {
        await _reviews.DeleteAsync(id, CurrentUserId, User.IsInRole("Admin"));
        return NoContent();
    }

    /// <summary>Запустить повторный LLM-анализ отзыва.</summary>
    /// <remarks>
    /// Только Admin. Сбрасывает статус отзыва на `Pending` и отправляет его
    /// на повторную обработку.
    /// </remarks>
    /// <param name="id">ID отзыва.</param>
    /// <response code="204">Повторный анализ запланирован.</response>
    /// <response code="401">Требуется аутентификация.</response>
    /// <response code="403">Требуется роль Admin.</response>
    /// <response code="404">Отзыв не найден.</response>
    [Authorize(Roles = "Admin")]
    [HttpPost("{id:int}/reanalyze")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> Reanalyze(int id)
    {
        await _reviews.ReanalyzeAsync(id);
        return NoContent();
    }
}
