using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PlotLine.Services;
using PlotLine.ViewModels;

namespace PlotLine.Controllers;

[Authorize]
public sealed class FeatureRequestsController(
    ICurrentUserService currentUser,
    IFeatureRequestService featureRequests,
    IEmailService emails) : Controller
{
    [HttpGet]
    public async Task<IActionResult> Index()
    {
        var userId = RequireUserId();
        var requests = await featureRequests.ListForUserAsync(userId);
        return View(new FeatureRequestIndexViewModel { Requests = requests });
    }

    [HttpGet]
    public IActionResult Create()
    {
        return View(new FeatureRequestCreateViewModel());
    }

    [HttpGet]
    public async Task<IActionResult> Roadmap()
    {
        return View(new FeatureRequestRoadmapViewModel
        {
            Sections = await featureRequests.ListRoadmapAsync()
        });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(FeatureRequestCreateViewModel model)
    {
        if (!ModelState.IsValid)
        {
            return View(WithOptions(model));
        }

        var created = await featureRequests.CreateAsync(RequireUserId(), model);
        TempData["FeatureRequestMessage"] = "Your feature request has been submitted.";
        return RedirectToAction(nameof(Details), new { id = created.FeatureRequestID });
    }

    [HttpGet]
    public async Task<IActionResult> Details(int id)
    {
        var request = await featureRequests.GetForUserAsync(id, RequireUserId());
        if (request is null)
        {
            return NotFound();
        }

        await featureRequests.MarkViewedForUserAsync(request.FeatureRequestID, request.UserID);
        request.UserNeedsAttention = false;
        request.UserAttentionUtc = null;

        return View(new FeatureRequestDetailsViewModel
        {
            Request = request,
            Messages = await featureRequests.ListMessagesAsync(request.FeatureRequestID),
            Reply = new FeatureRequestReplyViewModel { FeatureRequestID = request.FeatureRequestID }
        });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Reply([Bind(Prefix = "Reply")] FeatureRequestReplyViewModel model)
    {
        var userId = RequireUserId();
        var request = await featureRequests.GetForUserAsync(model.FeatureRequestID, userId);
        if (request is null)
        {
            return NotFound();
        }

        if (!ModelState.IsValid)
        {
            return View(nameof(Details), new FeatureRequestDetailsViewModel
            {
                Request = request,
                Messages = await featureRequests.ListMessagesAsync(request.FeatureRequestID),
                Reply = model
            });
        }

        await featureRequests.AddUserReplyAsync(model.FeatureRequestID, userId, model.MessageBody);
        await emails.SendFeatureRequestUserReplyAsync(
            request,
            Preview(model.MessageBody),
            BuildAbsoluteUrl("FeatureRequestDetails", "Admin", new { id = request.FeatureRequestID }),
            currentUser.Email ?? string.Empty);
        return RedirectToAction(nameof(Details), new { id = model.FeatureRequestID });
    }

    private int RequireUserId()
    {
        return currentUser.UserId ?? throw new InvalidOperationException("Authenticated user id was not available.");
    }

    private static FeatureRequestCreateViewModel WithOptions(FeatureRequestCreateViewModel model)
    {
        model.AppAreas = PlotLine.Models.FeatureRequestOptions.AppAreas;
        model.ImportanceOptions = PlotLine.Models.FeatureRequestOptions.ImportanceOptions;
        return model;
    }

    private string BuildAbsoluteUrl(string action, string controller, object routeValues)
    {
        return Url.Action(action, controller, routeValues, Request.Scheme)
            ?? $"{Request.Scheme}://{Request.Host}";
    }

    private static string Preview(string value)
    {
        var cleaned = value.ReplaceLineEndings(" ").Trim();
        return cleaned.Length <= 240 ? cleaned : $"{cleaned[..240]}...";
    }
}
