using System.ComponentModel.DataAnnotations;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.RateLimiting;
using TaxBaik.Web.Services;

namespace TaxBaik.Web.Pages.Admin;

[EnableRateLimiting("admin-login")]
public class LoginModel(AuthService authService) : PageModel
{
    private const string RememberedUsernameCookieName = "TaxBaik.Admin.RememberedUsername";

    [BindProperty]
    [Display(Name = "사용자명")]
    [Required(ErrorMessage = "사용자명을 입력하세요.")]
    public string Username { get; set; } = string.Empty;

    [BindProperty]
    [Display(Name = "비밀번호")]
    [DataType(DataType.Password)]
    [Required(ErrorMessage = "비밀번호를 입력하세요.")]
    public string Password { get; set; } = string.Empty;

    [BindProperty]
    [Display(Name = "아이디 기억하기")]
    public bool RememberUsername { get; set; } = true;

    [BindProperty(SupportsGet = true)]
    public string? ReturnUrl { get; set; }

    public string? ErrorMessage { get; set; }
    public string RedirectUrl { get; set; } = "/admin/dashboard";

    public void OnGet()
    {
        if (Request.Cookies.TryGetValue(RememberedUsernameCookieName, out var rememberedUsername) &&
            !string.IsNullOrWhiteSpace(rememberedUsername))
        {
            Username = rememberedUsername;
            RememberUsername = true;
        }

        if (!string.IsNullOrWhiteSpace(ReturnUrl))
        {
            RedirectUrl = NormalizeRedirectUrl(ReturnUrl);
        }
    }

    public async Task<IActionResult> OnPostAsync(CancellationToken ct)
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        var user = await authService.AuthenticateAsync(Username, Password);
        if (user is null)
        {
            ErrorMessage = "아이디 또는 비밀번호가 올바르지 않습니다.";
            return Page();
        }

        RedirectUrl = NormalizeRedirectUrl(ReturnUrl);

        var claims = new List<Claim>
        {
            new(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new(ClaimTypes.Name, user.Username),
            new(ClaimTypes.Role, "Admin")
        };

        var identity = new ClaimsIdentity(claims, AdminAuthDefaults.Scheme);
        var principal = new ClaimsPrincipal(identity);
        if (RememberUsername)
        {
            Response.Cookies.Append(
                RememberedUsernameCookieName,
                user.Username,
                new CookieOptions
                {
                    HttpOnly = true,
                    Secure = Request.IsHttps,
                    SameSite = SameSiteMode.Lax,
                    Expires = DateTimeOffset.UtcNow.AddDays(30)
                });
        }
        else
        {
            Response.Cookies.Delete(RememberedUsernameCookieName);
        }

        var properties = new AuthenticationProperties
        {
            IsPersistent = true,
            ExpiresUtc = DateTimeOffset.UtcNow.AddHours(12),
            RedirectUri = RedirectUrl
        };

        await HttpContext.SignInAsync(AdminAuthDefaults.Scheme, principal, properties);
        return LocalRedirect(RedirectUrl);
    }

    private static string NormalizeRedirectUrl(string? returnUrl)
    {
        if (string.IsNullOrWhiteSpace(returnUrl))
            return "/admin/dashboard";

        if (Uri.TryCreate(returnUrl, UriKind.Relative, out var relative))
        {
            var value = relative.ToString();
            if (value.StartsWith('/'))
                return value;  // 절대 경로는 그대로 사용 (/admin/dashboard 등)
            return $"/{value}";  // 상대 경로는 /로 시작하도록
        }

        if (Uri.TryCreate(returnUrl, UriKind.Absolute, out var absolute))
        {
            if (string.Equals(absolute.Host, "www.taxbaik.com", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(absolute.Host, "taxbaik.com", StringComparison.OrdinalIgnoreCase))
            {
                var path = absolute.PathAndQuery;
                return path;
            }
        }

        return "/admin/dashboard";
    }
}
