namespace CSR.WebUI.Pages;

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using CSR.Application.Interfaces;
using CSR.Domain.Entities;
using System.Collections.Generic;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using System.Security.Claims;

public class AuthModel(IUserService userService) : PageModel
{
  private readonly IUserService _userService = userService;

  [BindProperty]
  public InputModel Input { get; set; } = new();

  public List<string> ErrorMessages { get; set; } = [];

  public class InputModel
  {
    [Required(ErrorMessage = "Username is required.")]
    [Display(Name = "Username")]
    [StringLength(32, ErrorMessage = "Username cannot be longer than 32 characters.")]
    [RegularExpression(@"^[a-zA-Z0-9_]+$", ErrorMessage = "Username can only contain letters, numbers and underscore.")]
    public string Username { get; set; } = string.Empty;

    [EmailAddress]
    [Display(Name = "Email")]
    public string? Email { get; set; } = string.Empty;

    [Required(ErrorMessage = "Password is required.")]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; } = string.Empty;
  }

  public void OnGet()
  {
    ErrorMessages.Clear();
  }

  public async Task<IActionResult> OnPostLoginAsync()
  {
    // Clear any previous registration errors
    ModelState.Remove("Input.Email");

    if (!ModelState.IsValid)
    {
      foreach (var modelState in ModelState.Values)
      {
        foreach (var e in modelState.Errors)
        {
          ErrorMessages.Add(e.ErrorMessage);
        }
      }
      return Page();
    }

    var (user, error) = await _userService.Login(Input.Username, Input.Password);

    if (user == null)
    {
      ErrorMessages.Add(error ?? "Login failed.");
      Console.WriteLine(error);
      return Page();
    }

    await SendCookies(user.Username, user.Role.Name);

    return RedirectToPageBasedOnRole(user);
  }

  public async Task<IActionResult> OnPostLogoutAsync()
  {
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    return RedirectToPage("/Index"); // Redirect to home page after logout
  }

  public async Task<IActionResult> OnPostRegisterAsync()
  {
    // Email is required for registration, so add a validation error if it's missing
    if (string.IsNullOrWhiteSpace(Input.Email))
    {
      ModelState.AddModelError("Input.Email", "Email is required for registration.");
    }

    if (!ModelState.IsValid)
    {
      foreach (var modelState in ModelState.Values)
      {
        foreach (var error in modelState.Errors)
        {
          ErrorMessages.Add(error.ErrorMessage);
        }
      }
      return Page();
    }

    var result = await _userService.RegisterNewUser(Input.Username, Input.Email!, Input.Password);

    if (result.User != null)
    {
      await _userService.Login(Input.Username, Input.Password);
      await SendCookies(result.User.Username, result.User.Role.Name);
      return RedirectToPageBasedOnRole(result.User);
    }
    else
    {
      if (result.Errors != null)
      {
        ErrorMessages.AddRange(result.Errors);
      }
      else
      {
        ErrorMessages.Add("An unknown error occurred during registration.");
      }
      return Page();
    }
  }

  private async Task SendCookies(string username, string role)
  {
    var claims = new List<Claim>
        {
            new(ClaimTypes.Name, username),
            new(ClaimTypes.Role, role)
        };

    var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
    var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);

    var authProperties = new AuthenticationProperties
    {
      IsPersistent = true,
      ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(5)
    };

    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal, authProperties);
  }

  private RedirectToPageResult RedirectToPageBasedOnRole(User user)
  {
    if (user == null || string.IsNullOrWhiteSpace(user.Role.Name))
    {
      return RedirectToPage("/Index");
    }

    return user.Role.Name switch
    {
      "Admin" => RedirectToPage("/Admin"),
      "User" => RedirectToPage("/User"),
      _ => RedirectToPage("/Index"),
    };
  }
}
