using System.Reflection;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Security.Claims;
using QuantEngine.Web.Services;

namespace QuantEngine.Web.Pages.Account;

[AllowAnonymous]
public class LoginModel : PageModel
{
    private readonly AuthService _authService;
    private readonly IIpLockoutService _lockoutService;
    private readonly ILogger<LoginModel> _logger;

    public string? Username { get; set; }
    public bool RememberUsername { get; set; }
    public string? ErrorMessage { get; set; }
    public string AppVersion
    {
        get
        {
            // 1. Try reading version.txt from application base directory
            try
            {
                var txtPath = Path.Combine(AppContext.BaseDirectory, "version.txt");
                if (System.IO.File.Exists(txtPath))
                {
                    var txtVersion = System.IO.File.ReadAllText(txtPath).Trim();
                    if (!string.IsNullOrEmpty(txtVersion))
                        return txtVersion;
                }
            }
            catch {}

            // 2. Try reading raw assembly version
            var rawVersion = Assembly.GetEntryAssembly()
                ?.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
                ?.InformationalVersion;

            if (!string.IsNullOrEmpty(rawVersion) && rawVersion.StartsWith("quant_", StringComparison.OrdinalIgnoreCase))
            {
                return rawVersion;
            }

            // 3. Fallback to dynamic local Git parsing if available
            var dateStr = DateTime.UtcNow.AddHours(9).ToString("yyyyMMdd");
            string gitHash = "024122d";
            try
            {
                var baseDir = AppContext.BaseDirectory;
                var current = new DirectoryInfo(baseDir);
                string? repoRoot = null;
                while (current != null)
                {
                    if (Directory.Exists(Path.Combine(current.FullName, ".git")))
                    {
                        repoRoot = current.FullName;
                        break;
                    }
                    current = current.Parent;
                }
                if (repoRoot != null)
                {
                    var headPath = Path.Combine(repoRoot, ".git", "HEAD");
                    if (System.IO.File.Exists(headPath))
                    {
                        var headContent = System.IO.File.ReadAllText(headPath).Trim();
                        if (headContent.StartsWith("ref:"))
                        {
                            var refPath = Path.Combine(repoRoot, ".git", headContent.Substring(4).Trim().Replace('/', Path.DirectorySeparatorChar));
                            if (System.IO.File.Exists(refPath))
                            {
                                var fullHash = System.IO.File.ReadAllText(refPath).Trim();
                                if (fullHash.Length >= 7)
                                    gitHash = fullHash.Substring(0, 7);
                            }
                        }
                        else if (headContent.Length >= 7)
                        {
                            gitHash = headContent.Substring(0, 7);
                        }
                    }
                }
            }
            catch {}

            int runCount = 11;
            return $"quant_{dateStr}.{runCount}.{gitHash}";
        }
    }

    public LoginModel(AuthService authService, IIpLockoutService lockoutService, ILogger<LoginModel> logger)
    {
        _authService = authService;
        _lockoutService = lockoutService;
        _logger = logger;
    }

    public void OnGet()
    {
        if (Request.Cookies.TryGetValue("quant_admin_username", out var savedUsername))
        {
            Username = savedUsername;
            RememberUsername = true;
        }
    }

    public async Task<IActionResult> OnPostAsync(string username, string password, bool rememberUsername)
    {
        if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
        {
            ErrorMessage = "아이디와 비밀번호를 모두 입력해 주세요.";
            Username = username;
            RememberUsername = rememberUsername;
            return Page();
        }

        var ipAddress = HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown";

        var account = await _authService.AuthenticateAsync(username, password, ipAddress);
        if (account is null)
        {
            if (_lockoutService.IsLockedOut(ipAddress))
                ErrorMessage = "로그인 시도 횟수를 초과했습니다. 15분 후에 다시 시도해 주세요.";
            else
                ErrorMessage = "아이디 또는 비밀번호가 올바르지 않습니다.";

            Username = username;
            RememberUsername = rememberUsername;
            return Page();
        }

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

        var identity = new ClaimsIdentity(claims, AdminAuthDefaults.Scheme);
        var principal = new ClaimsPrincipal(identity);

        var properties = new Microsoft.AspNetCore.Authentication.AuthenticationProperties
        {
            IsPersistent = true,
            ExpiresUtc = DateTimeOffset.UtcNow.AddHours(12)
        };

        await HttpContext.SignInAsync(AdminAuthDefaults.Scheme, principal, properties);

        if (rememberUsername)
        {
            Response.Cookies.Append(
                "quant_admin_username",
                username,
                new Microsoft.AspNetCore.Http.CookieOptions
                {
                    Expires = DateTimeOffset.UtcNow.AddDays(30),
                    HttpOnly = false,
                    SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict
                }
            );
        }
        else
        {
            Response.Cookies.Delete("quant_admin_username");
        }

        _logger.LogInformation("[Login] User '{Username}' authenticated successfully from {IpAddress}", account.Username, ipAddress);
        return LocalRedirect("/Admin/Dashboard");
    }
}
