using System.Security.Claims;
using System.Text;
using System.Text.Json;
using Eshop.Application.Auth;
using Eshop.Web.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Eshop.Web.Controllers;

public class AuthController : Controller
{
    private readonly ILogger<AuthController> _logger;
    private readonly IAuthenticationService _authenticationService;
    private readonly IUserAccountService _userAccountService;

    public AuthController(
        ILogger<AuthController> logger,
        IAuthenticationService authenticationService,
        IUserAccountService userAccountService)
    {
        _logger = logger;
        _authenticationService = authenticationService;
        _userAccountService = userAccountService;
    }

    #region HttpGet

    [HttpGet]
    [AllowAnonymous]
    public IActionResult Login(string? returnUrl)
    {
        if (User.Identity?.IsAuthenticated == true)
            return RedirectToAction("Index", "Home");

        return View(new AuthLoginViewModel { ReturnUrl = returnUrl });
    }

    [HttpGet]
    [AllowAnonymous]
    public IActionResult Register(string? returnUrl)
    {
        if (User.Identity?.IsAuthenticated == true)
            return RedirectToAction("Index", "Home");

        return View(new AuthRegisterViewModel { ReturnUrl = returnUrl });
    }

    [HttpGet]
    public IActionResult AccessDenied() => View();

    [HttpGet]
    [Authorize]
    public async Task<IActionResult> Profile()
    {
        var userId = GetCurrentUserId();
        if (userId is null) return RedirectToAction("Login");

        var profile = await _userAccountService.GetProfileAsync(userId);
        if (profile is null) return RedirectToAction("Login");

        return View(new ProfileViewModel
        {
            UserName = profile.UserName,
            Email = profile.Email,
        });
    }

    #endregion

    #region HttpPost

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Login(AuthLoginViewModel model)
    {
        if (!ModelState.IsValid) return View(model);

        var result = await _authenticationService.SignInAsync(
            model.EmailOrUsername, model.Password, model.RememberMe);

        if (!result.Succeeded)
        {
            ModelState.AddModelError(string.Empty, "Invalid credentials.");
            return View(model);
        }

        if (!string.IsNullOrEmpty(model.ReturnUrl) && Url.IsLocalUrl(model.ReturnUrl))
            return Redirect(model.ReturnUrl);

        return RedirectToAction("Index", "Home");
    }

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Register(AuthRegisterViewModel model)
    {
        if (!ModelState.IsValid) return View(model);

        var result = await _userAccountService.RegisterAsync(
            model.UserName, model.Email, model.Password);

        if (!result.Success)
        {
            foreach (var error in result.Errors)
                ModelState.AddModelError(string.Empty, error);
            return View(model);
        }

        _logger.LogInformation("User {UserName} registered.", model.UserName);

        if (!string.IsNullOrEmpty(model.ReturnUrl) && Url.IsLocalUrl(model.ReturnUrl))
            return Redirect(model.ReturnUrl);

        return RedirectToAction("Login");
    }

    [HttpPost]
    [Authorize]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Profile(ProfileViewModel model)
    {
        if (!ModelState.IsValid) return View(model);

        var userId = GetCurrentUserId();
        if (userId is null) return RedirectToAction("Login");

        var result = await _userAccountService.UpdateProfileAsync(
            userId,
            new UpdateProfileRequest(
                model.UserName,
                model.Email,
                model.CurrentPassword,
                model.NewPassword));

        if (!result.Success)
        {
            foreach (var error in result.Errors)
                ModelState.AddModelError(string.Empty, error);
            return View(model);
        }

        TempData["SuccessMessage"] = "Profile updated successfully.";
        return RedirectToAction("Profile");
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Logout()
    {
        await _authenticationService.SignOutAsync();
        return RedirectToAction("Index", "Home");
    }

    [HttpPost]
    [Authorize]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteAccount()
    {
        var userId = GetCurrentUserId();
        if (userId is null) return RedirectToAction("Login");

        var result = await _userAccountService.DeleteAccountAsync(userId);
        if (!result.Success)
        {
            foreach (var error in result.Errors)
                ModelState.AddModelError(string.Empty, error);
            return RedirectToAction("Profile");
        }

        _logger.LogInformation("User {UserId} deleted their account.", userId);
        return RedirectToAction("Register");
    }

    [HttpGet]
    [Authorize]
    public async Task<IActionResult> DownloadData()
    {
        var userId = GetCurrentUserId();
        if (userId is null) return RedirectToAction("Login");

        var data = await _userAccountService.ExportUserDataAsync(userId);
        if (data is null) return RedirectToAction("Login");

        var export = new
        {
            data.Id,
            data.UserName,
            data.Email,
            Roles = data.Roles,
            data.ExportDate,
        };

        var json = JsonSerializer.Serialize(export, new JsonSerializerOptions { WriteIndented = true });
        var bytes = Encoding.UTF8.GetBytes(json);

        return File(bytes, "application/json", $"user_data_{data.UserName}.json");
    }

    #endregion

    private string? GetCurrentUserId() =>
        User.FindFirstValue(ClaimTypes.NameIdentifier);
}
