using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Prototype.MvcWsHtmx.Models;
using System.Diagnostics;
using System.Net.WebSockets;
using System.Text.Json;
using System.Text;
using System.Text.Json.Nodes;

namespace Prototype.MvcWsHtmx.Controllers;
public class HomeController : Controller
{
    private readonly Messages _msgs;

    public HomeController(Messages msgs)
    {
        _msgs = msgs;
    }

    public IActionResult Index()
    {
        HomeViewModel model = new HomeViewModel();
        model.LastMessages = _msgs.TakeLast(5).ToList();
        return View(model);
    }

    public async Task Messages()
    {
        if (HttpContext.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
            var buffer = new byte[1024 * 4];
            WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            while (!result.CloseStatus.HasValue)
            {
                var messageJson = Encoding.UTF8.GetString(buffer, 0, result.Count);

                var messageObject = JsonSerializer.Deserialize<JsonObject>(messageJson);
                var message = new Message
                {
                    Text = messageObject["text"]?.ToString(),
                    Title = messageObject["title"]?.ToString(),
                    Time = DateTime.Now.ToString("HH:mm:ss")
                };  
                _msgs.Add(message);
                var htmlString = await RenderViewAsync("Message", message, true);
                var bytes = Encoding.UTF8.GetBytes(htmlString);
                await webSocket.SendAsync(new ArraySegment<byte>(bytes, 0, bytes.Length), result.MessageType, result.EndOfMessage, CancellationToken.None);

                result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            }
            await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
        }
        else
        {
            HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }

    private async Task<string> RenderViewAsync(string viewName, object model, bool partial = false)
    {
        if (string.IsNullOrEmpty(viewName))
        {
            viewName = ControllerContext.ActionDescriptor.ActionName;
        }

        ViewData.Model = model;

        using (var writer = new StringWriter())
        {
            IViewEngine viewEngine = HttpContext.RequestServices.GetRequiredService<ICompositeViewEngine>();
            ViewEngineResult viewResult = viewEngine.FindView(ControllerContext, viewName, !partial);

            if (viewResult.Success)
            {
                ViewContext viewContext = new ViewContext(
                    ControllerContext,
                    viewResult.View,
                    ViewData,
                    TempData,
                    writer,
                    new HtmlHelperOptions()
                );

                await viewResult.View.RenderAsync(viewContext);
            }

            return writer.GetStringBuilder().ToString();
        }
    }

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}
