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

namespace PlotLine.Controllers;

[Authorize]
public sealed class ProjectRestorePointsController(
    IProjectRestorePointService restorePoints,
    IProjectRestoreService projectRestore,
    ILogger<ProjectRestorePointsController> logger) : Controller
{
    public async Task<IActionResult> Index(int projectId)
    {
        var model = await restorePoints.GetAsync(projectId);
        return model is null ? NotFound() : View(model);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(int projectId, string? restorePointName, string? notes)
    {
        try
        {
            if (await restorePoints.HasReachedManualLimitAsync(projectId))
            {
                TempData["ProjectRestorePointMessage"] = ProjectRestorePointService.LimitReachedMessage;
                return RedirectToAction(nameof(Index), new { projectId });
            }

            var created = await restorePoints.CreateManualAsync(projectId, restorePointName, notes);
            TempData["ProjectRestorePointMessage"] = created is null
                ? "Restore point could not be created because the project was not found."
                : "Restore point created.";
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Manual restore point creation failed for project {ProjectID}.", projectId);
            TempData["ProjectRestorePointMessage"] = "Restore point could not be created. Please try again, or check the application logs if the problem continues.";
        }

        return RedirectToAction(nameof(Index), new { projectId });
    }

    public async Task<IActionResult> Download(int projectId, int id)
    {
        try
        {
            var download = await restorePoints.DownloadAsync(id, projectId);
            if (download is null)
            {
                TempData["ProjectRestorePointMessage"] = "Restore point could not be found.";
                return RedirectToAction(nameof(Index), new { projectId });
            }

            return File(System.Text.Encoding.UTF8.GetBytes(download.Json), download.ContentType, download.FileName);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Restore point download failed for restore point {ProjectRestorePointID} in project {ProjectID}.", id, projectId);
            TempData["ProjectRestorePointMessage"] = "Restore point could not be downloaded. Please try again, or check the application logs if the problem continues.";
            return RedirectToAction(nameof(Index), new { projectId });
        }
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Restore(int projectId, int id)
    {
        try
        {
            var result = await projectRestore.RestoreAsync(projectId, id);
            TempData["ProjectRestorePointMessage"] = result.Message;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Project restore failed unexpectedly for restore point {ProjectRestorePointID} in project {ProjectID}.", id, projectId);
            TempData["ProjectRestorePointMessage"] = "Restore failed. No project data was changed.";
        }

        return RedirectToAction(nameof(Index), new { projectId });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Delete(int projectId, int id)
    {
        try
        {
            var deleted = await restorePoints.DeleteAsync(id, projectId);
            TempData["ProjectRestorePointMessage"] = deleted
                ? "Restore point deleted."
                : "Restore point could not be deleted. It may not exist.";
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Restore point delete failed unexpectedly for restore point {ProjectRestorePointID} in project {ProjectID}.", id, projectId);
            TempData["ProjectRestorePointMessage"] = "Restore point could not be deleted. Please try again, or check the application logs if the problem continues.";
        }

        return RedirectToAction(nameof(Index), new { projectId });
    }
}
