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

namespace PlotLine.Controllers;

[Authorize]
public sealed class FloorPlansController(IFloorPlanService floorPlans) : Controller
{
    public async Task<IActionResult> Index(int projectId)
    {
        var model = await floorPlans.ListAsync(projectId);
        return model is null ? NotFound() : View(model);
    }

    public async Task<IActionResult> Edit(int id)
    {
        var model = await floorPlans.GetEditorAsync(id);
        return model is null ? NotFound() : View(model);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(FloorPlanEditViewModel model)
    {
        if (!ModelState.IsValid)
        {
            return RedirectToAction(nameof(Index), new { projectId = model.ProjectID });
        }

        var floorPlanId = await floorPlans.SavePlanAsync(model);
        return RedirectToAction(nameof(Edit), new { id = floorPlanId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> SavePlan(FloorPlanEditViewModel model)
    {
        if (!ModelState.IsValid)
        {
            var editor = await floorPlans.GetEditorAsync(model.FloorPlanID);
            if (editor is null)
            {
                return NotFound();
            }

            editor.FloorPlan = model;
            return View("Edit", editor);
        }

        var floorPlanId = await floorPlans.SavePlanAsync(model);
        TempData["FloorPlanMessage"] = "Floor plan saved.";
        return RedirectToAction(nameof(Edit), new { id = floorPlanId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> SaveLayout(FloorPlanEditorViewModel model)
    {
        var isAsyncSave = string.Equals(Request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.OrdinalIgnoreCase);
        try
        {
            await floorPlans.SaveLayoutAsync(model);
            if (isAsyncSave)
            {
                return Json(new { ok = true, message = "Saved" });
            }

            TempData["FloorPlanMessage"] = "Layout saved.";
        }
        catch (InvalidOperationException ex)
        {
            if (isAsyncSave)
            {
                Response.StatusCode = StatusCodes.Status400BadRequest;
                return Json(new { ok = false, message = ex.Message });
            }

            TempData["FloorPlanError"] = ex.Message;
        }

        return RedirectToAction(nameof(Edit), new { id = model.FloorPlan.FloorPlanID });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeletePlan(int id, int projectId)
    {
        await floorPlans.DeletePlanAsync(id);
        TempData["FloorPlanMessage"] = "Floor plan deleted.";
        return RedirectToAction(nameof(Index), new { projectId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> AddFloor(FloorPlanFloorEditViewModel model)
    {
        if (ModelState.IsValid)
        {
            await floorPlans.SaveFloorAsync(model);
            TempData["FloorPlanMessage"] = "Floor added.";
        }

        return RedirectToAction(nameof(Edit), new { id = model.FloorPlanID });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteFloor(int floorPlanId, int floorPlanFloorId)
    {
        await floorPlans.DeleteFloorAsync(floorPlanFloorId);
        TempData["FloorPlanMessage"] = "Floor deleted.";
        return RedirectToAction(nameof(Edit), new { id = floorPlanId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> UploadBackground(int floorPlanId, int floorPlanFloorId, IFormFile? backgroundImage)
    {
        if (backgroundImage is null)
        {
            TempData["FloorPlanError"] = "Choose a background image to upload.";
            return RedirectToAction(nameof(Edit), new { id = floorPlanId });
        }

        var result = await floorPlans.UploadBackgroundAsync(floorPlanId, floorPlanFloorId, backgroundImage);
        TempData[result.Succeeded ? "FloorPlanMessage" : "FloorPlanError"] = result.Succeeded
            ? "Background image uploaded."
            : result.ErrorMessage ?? "Background image could not be uploaded.";
        return RedirectToAction(nameof(Edit), new { id = floorPlanId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> SaveBackgroundSettings(FloorPlanFloorBackgroundSettingsViewModel model)
    {
        var isAsyncSave = string.Equals(Request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.OrdinalIgnoreCase);
        try
        {
            await floorPlans.SaveBackgroundSettingsAsync(model);
            if (isAsyncSave)
            {
                return Json(new { ok = true, message = "Saved" });
            }

            TempData["FloorPlanMessage"] = "Background settings saved.";
        }
        catch (InvalidOperationException ex)
        {
            if (isAsyncSave)
            {
                Response.StatusCode = StatusCodes.Status400BadRequest;
                return Json(new { ok = false, message = ex.Message });
            }

            TempData["FloorPlanError"] = ex.Message;
        }

        return RedirectToAction(nameof(Edit), new { id = model.FloorPlanID });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> ResetBackground(int floorPlanId, int floorPlanFloorId)
    {
        await floorPlans.ResetBackgroundAsync(floorPlanId, floorPlanFloorId);
        TempData["FloorPlanMessage"] = "Background position reset.";
        return RedirectToAction(nameof(Edit), new { id = floorPlanId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> RemoveBackground(int floorPlanId, int floorPlanFloorId)
    {
        await floorPlans.RemoveBackgroundAsync(floorPlanId, floorPlanFloorId);
        TempData["FloorPlanMessage"] = "Background image removed.";
        return RedirectToAction(nameof(Edit), new { id = floorPlanId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> SaveTransition(int floorPlanId, FloorPlanTransitionEditViewModel model)
    {
        try
        {
            if (ModelState.IsValid)
            {
                await floorPlans.SaveTransitionAsync(floorPlanId, model);
                TempData["FloorPlanMessage"] = model.FloorPlanTransitionID == 0 ? "Transition created." : "Transition updated.";
            }
        }
        catch (InvalidOperationException ex)
        {
            TempData["FloorPlanError"] = ex.Message;
        }

        return RedirectToAction(nameof(Edit), new { id = floorPlanId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteTransition(int floorPlanId, int floorPlanTransitionId)
    {
        try
        {
            await floorPlans.DeleteTransitionAsync(floorPlanId, floorPlanTransitionId);
            TempData["FloorPlanMessage"] = "Transition deleted.";
        }
        catch (InvalidOperationException ex)
        {
            TempData["FloorPlanError"] = ex.Message;
        }

        return RedirectToAction(nameof(Edit), new { id = floorPlanId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> AddBlock(int floorPlanId, FloorPlanBlockEditViewModel model)
    {
        var isAsyncSave = string.Equals(Request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.OrdinalIgnoreCase);
        try
        {
            if (ModelState.IsValid)
            {
                var floorPlanBlockId = await floorPlans.SaveBlockAsync(model);
                if (isAsyncSave)
                {
                    var block = await floorPlans.GetBlockAsync(floorPlanBlockId);
                    if (block is null)
                    {
                        Response.StatusCode = StatusCodes.Status400BadRequest;
                        return Json(new { ok = false, message = "Block was saved but could not be loaded." });
                    }

                    return Json(new
                    {
                        ok = true,
                        message = "Saved",
                        block = new
                        {
                            block.FloorPlanBlockID,
                            block.FloorPlanFloorID,
                            block.LocationID,
                            block.LocationName,
                            block.LocationPath,
                            block.DisplayLabel,
                            block.X,
                            block.Y,
                            block.WidthCells,
                            block.HeightCells,
                            block.BlockType,
                            block.LabelOverride,
                            block.Notes
                        }
                    });
                }

                TempData["FloorPlanMessage"] = "Block added.";
                return RedirectToAction(nameof(Edit), new { id = floorPlanId, selectedBlockId = floorPlanBlockId });
            }
        }
        catch (InvalidOperationException ex)
        {
            if (isAsyncSave)
            {
                Response.StatusCode = StatusCodes.Status400BadRequest;
                return Json(new { ok = false, message = ex.Message });
            }

            TempData["FloorPlanError"] = ex.Message;
        }

        if (isAsyncSave)
        {
            Response.StatusCode = StatusCodes.Status400BadRequest;
            return Json(new { ok = false, message = "Block could not be added." });
        }

        return RedirectToAction(nameof(Edit), new { id = floorPlanId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteBlock(int floorPlanId, int floorPlanBlockId)
    {
        await floorPlans.DeleteBlockAsync(floorPlanBlockId);
        TempData["FloorPlanMessage"] = "Block deleted.";
        return RedirectToAction(nameof(Edit), new { id = floorPlanId });
    }
}
