using System.Text.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PlotLine.Data;
using PlotLine.Services;
using PlotLine.ViewModels;

namespace PlotLine.Controllers;

[Authorize]
public sealed class ManageAccountController(
    ICurrentUserService currentUser,
    IUserRepository users,
    IAuthService authService,
    ITwoFactorService twoFactorService,
    ISubscriptionService subscriptions) : Controller
{
    [HttpGet]
    public async Task<IActionResult> Index()
    {
        var user = await GetCurrentUserAsync();
        if (user is null)
        {
            return RedirectToAction("Login", "Account");
        }

        return View(new ManageAccountViewModel
        {
            User = user,
            Subscription = await subscriptions.GetCurrentSubscriptionAsync(user.UserID)
        });
    }

    [HttpGet]
    public IActionResult ChangePassword()
    {
        return View(new ChangePasswordViewModel());
    }

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

        var result = await authService.ChangePasswordAsync(model);
        if (!result.Success)
        {
            ModelState.AddModelError(string.Empty, result.ErrorMessage ?? "Your password could not be changed.");
            return View(model);
        }

        TempData["AuthMessage"] = "Your password has been changed. Please sign in again.";
        return RedirectToAction("Login", "Account");
    }

    [HttpGet]
    public async Task<IActionResult> EnableTwoFactor()
    {
        var user = await GetCurrentUserAsync();
        if (user is null)
        {
            return RedirectToAction("Login", "Account");
        }

        var secret = twoFactorService.GenerateSecretKey();
        var uri = twoFactorService.GenerateQrCodeUri(user.Email, secret);
        return View(new EnableTwoFactorViewModel
        {
            SecretKey = secret,
            QrCodeUri = uri,
            QrCodeImageDataUri = twoFactorService.GenerateQrCodeDataUri(uri)
        });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> EnableTwoFactor(EnableTwoFactorViewModel model)
    {
        if (!ModelState.IsValid)
        {
            model.QrCodeUri = twoFactorService.GenerateQrCodeUri(currentUser.Email ?? string.Empty, model.SecretKey);
            model.QrCodeImageDataUri = twoFactorService.GenerateQrCodeDataUri(model.QrCodeUri);
            return View(model);
        }

        var result = await authService.EnableTwoFactorAsync(currentUser.UserId!.Value, model.SecretKey, model.Code);
        if (!result.Success)
        {
            ModelState.AddModelError(string.Empty, result.ErrorMessage ?? "Two-factor authentication could not be enabled.");
            model.QrCodeUri = twoFactorService.GenerateQrCodeUri(currentUser.Email ?? string.Empty, model.SecretKey);
            model.QrCodeImageDataUri = twoFactorService.GenerateQrCodeDataUri(model.QrCodeUri);
            return View(model);
        }

        TempData["RecoveryCodes"] = JsonSerializer.Serialize(result.RecoveryCodes);
        TempData["AuthMessage"] = "Two-factor authentication has been enabled.";
        return RedirectToAction(nameof(RecoveryCodes));
    }

    [HttpGet]
    public IActionResult DisableTwoFactor()
    {
        return View(new DisableTwoFactorViewModel());
    }

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

        var result = await authService.DisableTwoFactorAsync(currentUser.UserId!.Value, model.CurrentPassword);
        if (!result.Success)
        {
            ModelState.AddModelError(string.Empty, result.ErrorMessage ?? "Two-factor authentication could not be disabled.");
            return View(model);
        }

        TempData["AuthMessage"] = "Two-factor authentication has been disabled.";
        return RedirectToAction(nameof(Index));
    }

    [HttpGet]
    public IActionResult RecoveryCodes()
    {
        var codes = TempData["RecoveryCodes"] is string json
            ? JsonSerializer.Deserialize<IReadOnlyList<string>>(json) ?? Array.Empty<string>()
            : Array.Empty<string>();

        return View(new RecoveryCodesViewModel { RecoveryCodes = codes });
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> RegenerateRecoveryCodes()
    {
        var codes = await authService.GenerateRecoveryCodesAsync(currentUser.UserId!.Value);
        TempData["RecoveryCodes"] = JsonSerializer.Serialize(codes);
        TempData["AuthMessage"] = "New recovery codes have been generated.";
        return RedirectToAction(nameof(RecoveryCodes));
    }

    private async Task<PlotLine.Models.AppUser?> GetCurrentUserAsync()
    {
        return currentUser.UserId is int userId ? await users.GetByIdAsync(userId) : null;
    }
}
