using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using TaxBaik.Application.Services;
using TaxBaik.Web.Services;

namespace TaxBaik.Web.Pages.Portal;

public class ExternalCallbackModel : PageModel
{
    private readonly PortalUserService _portalUserService;
    private readonly ClientService _clientService;

    public ExternalCallbackModel(PortalUserService portalUserService, ClientService clientService)
    {
        _portalUserService = portalUserService;
        _clientService = clientService;
    }

    public async Task<IActionResult> OnGetAsync(string provider)
    {
        var external = await HttpContext.AuthenticateAsync(PortalOAuthDefaults.ExternalScheme);
        if (external?.Principal is null)
            return RedirectToPage("/Portal/Login");

        var email = external.Principal.FindFirstValue(ClaimTypes.Email);
        var name = external.Principal.FindFirstValue(ClaimTypes.Name) ?? "고객";
        var providerId = external.Principal.FindFirstValue(ClaimTypes.NameIdentifier) ?? "";

        if (string.IsNullOrWhiteSpace(providerId))
            return RedirectToPage("/Portal/Login");

        var existing = await _portalUserService.GetByProviderAsync(provider, providerId);
        if (existing is null && !string.IsNullOrWhiteSpace(email))
        {
            existing = await _portalUserService.GetByEmailAsync(email);
            if (existing is null)
            {
                int? clientId = null;
                var linkedClient = await _clientService.GetByEmailAsync(email);
                if (linkedClient is null && !string.IsNullOrWhiteSpace(external.Principal.FindFirstValue("phone")))
                    linkedClient = await _clientService.GetByPhoneAsync(external.Principal.FindFirstValue("phone")!);
                if (linkedClient is not null)
                    clientId = linkedClient.Id;

                await _portalUserService.RegisterOAuthAsync(
                    name,
                    email,
                    external.Principal.FindFirstValue("phone") ?? "",
                    provider,
                    providerId,
                    clientId);
                existing = await _portalUserService.GetByEmailAsync(email);
            }
            else if (!string.Equals(existing.Provider, provider, StringComparison.OrdinalIgnoreCase) ||
                     !string.Equals(existing.ProviderId, providerId, StringComparison.OrdinalIgnoreCase))
            {
                await _portalUserService.LinkOAuthAsync(existing, provider, providerId, name, email);
            }
        }

        if (existing is not null && !existing.ClientId.HasValue && !string.IsNullOrWhiteSpace(email))
        {
            var linkedClient = await _clientService.GetByEmailAsync(email);
            if (linkedClient is null && !string.IsNullOrWhiteSpace(external.Principal.FindFirstValue("phone")))
                linkedClient = await _clientService.GetByPhoneAsync(external.Principal.FindFirstValue("phone")!);
            if (linkedClient is not null)
            {
                await _portalUserService.AttachClientAsync(existing, linkedClient.Id);
                existing.ClientId = linkedClient.Id;
            }
        }

        if (existing is null)
            return RedirectToPage("/Portal/Login");

        var claims = new List<Claim>
        {
            new(ClaimTypes.NameIdentifier, existing.Id.ToString()),
            new(ClaimTypes.Name, existing.Name),
            new(ClaimTypes.Email, existing.Email),
            new("portal_user_id", existing.Id.ToString())
        };

        if (existing.ClientId.HasValue)
            claims.Add(new("client_id", existing.ClientId.Value.ToString()));

        await HttpContext.SignInAsync(
            PortalAuthDefaults.Scheme,
            new ClaimsPrincipal(new ClaimsIdentity(claims, PortalAuthDefaults.Scheme)),
            new AuthenticationProperties { IsPersistent = true });

        await HttpContext.SignOutAsync(PortalOAuthDefaults.ExternalScheme);
        return RedirectToPage("/Portal/Index");
    }
}
