using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using Nexus.Contracts.Auth;
using Nexus.Contracts.Users;
using NexusShell.Models;

namespace NexusShell.Services;

public sealed class AuthService
{
    private readonly HttpClient _httpClient;
    private readonly ProfileService _profileService;
    private readonly string _clientId;

    public AuthService(HttpClient httpClient, ProfileService profileService, string authority, string clientId)
    {
        _httpClient = httpClient;
        _profileService = profileService;
        _clientId = clientId;
        _httpClient.BaseAddress = new Uri(authority.TrimEnd('/') + "/");
    }

    public async Task<(bool Success, string? Error)> LoginAsync(string email, string password)
    {
        var (identityReady, identityError) = await IdentityHostService.EnsureRunningAsync(
            _httpClient.BaseAddress?.ToString().TrimEnd('/') ?? IdentityHostService.DefaultAuthority);
        if (!identityReady)
        {
            return (false, identityError);
        }

        try
        {
            var form = new FormUrlEncodedContent(new Dictionary<string, string>
            {
                ["grant_type"] = "password",
                ["username"] = email,
                ["password"] = password,
                ["client_id"] = _clientId,
            });

            var response = await _httpClient.PostAsync("connect/token", form);
            if (!response.IsSuccessStatusCode)
            {
                return (false, "Forkert email eller password");
            }

            var json = await response.Content.ReadAsStringAsync();
            var tokens = JsonSerializer.Deserialize<TokenResponse>(json, JsonOptions)
                ?? throw new InvalidOperationException("Invalid token response");

            await ApplyTokensAsync(tokens);
            return (true, null);
        }
        catch (HttpRequestException)
        {
            return (false, "Kan ikke forbinde til Identity API på localhost:5050. Brug NexusSetup.exe → Start Ninja Nexus.");
        }
        catch (Exception ex)
        {
            return (false, ex.Message);
        }
    }

    public async Task<bool> TryRestoreSessionAsync()
    {
        var stored = _profileService.LoadTokens();
        if (stored is null)
        {
            return false;
        }

        if (stored.ExpiresAt > DateTimeOffset.UtcNow.AddMinutes(1))
        {
            _profileService.SetAccessToken(stored.AccessToken);
            try
            {
                await LoadProfileAsync(stored.AccessToken);
                return true;
            }
            catch
            {
                _profileService.ClearSession();
                return false;
            }
        }

        if (string.IsNullOrWhiteSpace(stored.RefreshToken))
        {
            return false;
        }

        try
        {
            var form = new FormUrlEncodedContent(new Dictionary<string, string>
            {
                ["grant_type"] = "refresh_token",
                ["refresh_token"] = stored.RefreshToken,
                ["client_id"] = _clientId,
            });

            var response = await _httpClient.PostAsync("connect/token", form);
            if (!response.IsSuccessStatusCode)
            {
                _profileService.ClearSession();
                return false;
            }

            var json = await response.Content.ReadAsStringAsync();
            var tokens = JsonSerializer.Deserialize<TokenResponse>(json, JsonOptions)!;
            await ApplyTokensAsync(tokens);
            return true;
        }
        catch
        {
            _profileService.ClearSession();
            return false;
        }
    }

    public void Logout()
    {
        _profileService.ClearSession();
    }

    public string? AccessToken => _profileService.AccessToken;

    private async Task ApplyTokensAsync(TokenResponse tokens)
    {
        var expiresAt = DateTimeOffset.UtcNow.AddSeconds(tokens.ExpiresIn);
        _profileService.SaveTokens(new StoredTokens
        {
            AccessToken = tokens.AccessToken,
            RefreshToken = tokens.RefreshToken,
            IdToken = tokens.IdToken,
            ExpiresAt = expiresAt,
        });
        _profileService.SetAccessToken(tokens.AccessToken);
        await LoadProfileAsync(tokens.AccessToken);
    }

    private async Task LoadProfileAsync(string accessToken)
    {
        using var request = new HttpRequestMessage(HttpMethod.Get, "api/users/me");
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
        var response = await _httpClient.SendAsync(request);
        response.EnsureSuccessStatusCode();

        var json = await response.Content.ReadAsStringAsync();
        var profile = JsonSerializer.Deserialize<UserProfileDto>(json, JsonOptions)
            ?? throw new InvalidOperationException("Invalid profile response");

        _profileService.SaveProfile(new LocalUserProfile
        {
            UserId = profile.Id,
            Email = profile.Email,
            DisplayName = profile.DisplayName,
            Theme = profile.Theme,
            Role = profile.Role,
            RecentAppIds = _profileService.LoadProfile()?.RecentAppIds ?? [],
        });
    }

    private static readonly JsonSerializerOptions JsonOptions = new()
    {
        PropertyNameCaseInsensitive = true,
    };
}
