using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using SilverLabs.Website.Models;

namespace SilverLabs.Website.Services;

public class DeveloperApplicationService
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<DeveloperApplicationService> _logger;

    public DeveloperApplicationService(HttpClient httpClient, ILogger<DeveloperApplicationService> logger)
    {
        _httpClient = httpClient;
        _logger = logger;
    }

    /// <summary>
    /// Checks username availability. Returns: true = available, false = taken, null = error/unknown.
    /// </summary>
    public async Task<bool?> CheckUsernameAsync(string username)
    {
        try
        {
            var response = await _httpClient.GetAsync($"/api/auth/check-username/{Uri.EscapeDataString(username)}");
            if (!response.IsSuccessStatusCode)
            {
                _logger.LogWarning("Username check returned {StatusCode} for {Username}", response.StatusCode, username);
                return null;
            }

            var result = await response.Content.ReadFromJsonAsync<JsonElement>();
            if (result.TryGetProperty("available", out var available))
                return available.GetBoolean();

            return null;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error checking username availability for {Username}", username);
            return null;
        }
    }

    public async Task<(bool Success, string Message, string? Token)> SubmitApplicationAsync(DeveloperApplication application)
    {
        try
        {
            // 1. Register user on SilverDESK
            var registerPayload = new
            {
                username = application.DesiredUsername,
                email = application.Email,
                password = application.Password,
                fullName = application.FullName
            };

            var registerResponse = await _httpClient.PostAsJsonAsync("/api/auth/register", registerPayload);

            if (!registerResponse.IsSuccessStatusCode)
            {
                var errorBody = await registerResponse.Content.ReadAsStringAsync();
                _logger.LogError("SilverDESK registration failed: {StatusCode} - {Body}", registerResponse.StatusCode, errorBody);

                var friendlyMessage = ParseRegistrationError(errorBody);
                return (false, friendlyMessage, null);
            }

            var authResult = await registerResponse.Content.ReadFromJsonAsync<JsonElement>();
            var token = authResult.GetProperty("token").GetString();

            // 2. Create ticket using the user's own JWT
            var ticketBody = FormatTicketBody(application);
            var ticketPayload = new
            {
                Subject = $"[Developer Program] {application.Role} Application - {application.FullName}",
                Description = ticketBody,
                Priority = "Medium",
                Category = "Developer Program"
            };

            // Use a fresh HttpClient without the X-API-Key default header so that
            // SilverDESK's MultiAuth policy routes to Bearer/JWT auth (the new user's token)
            // instead of ApiKey auth (which resolves to the MCP system user).
            using var userClient = new HttpClient { BaseAddress = _httpClient.BaseAddress };
            var ticketRequest = new HttpRequestMessage(HttpMethod.Post, "/api/tickets");
            ticketRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
            ticketRequest.Content = JsonContent.Create(ticketPayload);

            var ticketResponse = await userClient.SendAsync(ticketRequest);

            if (!ticketResponse.IsSuccessStatusCode)
            {
                var errorBody = await ticketResponse.Content.ReadAsStringAsync();
                _logger.LogError("Failed to create ticket: {StatusCode} - {Body}", ticketResponse.StatusCode, errorBody);
                // User was created but ticket failed — still return success with a note
                return (true, "Your account has been created, but we had trouble submitting your application ticket. Please log in to SilverDESK and create a support ticket.", token);
            }

            // 3. Create DeveloperApplication record linking user + ticket
            try
            {
                var userId = authResult.GetProperty("user").GetProperty("id").GetString();
                var ticketResult = await ticketResponse.Content.ReadFromJsonAsync<JsonElement>();
                var ticketId = ticketResult.GetProperty("id").GetString();

                var applicationPayload = new
                {
                    userId,
                    ticketId,
                    fullName = application.FullName,
                    email = application.Email,
                    desiredUsername = application.DesiredUsername,
                    timezone = application.Timezone,
                    appliedRole = application.Role.ToString(),
                    platforms = application.Platforms,
                    skills = application.Skills ?? "",
                    motivation = application.Motivation,
                    status = 0, // Pending
                    silverDeskProvisioned = true
                };

                var appResponse = await _httpClient.PostAsJsonAsync("/api/developer-program/applications", applicationPayload);

                if (appResponse.IsSuccessStatusCode)
                {
                    _logger.LogInformation("DeveloperApplication record created for {Email}", application.Email);
                }
                else
                {
                    var appError = await appResponse.Content.ReadAsStringAsync();
                    _logger.LogWarning("Failed to create DeveloperApplication record for {Email}: {StatusCode} - {Body}",
                        application.Email, appResponse.StatusCode, appError);
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "Failed to create DeveloperApplication record for {Email} — user and ticket were created successfully",
                    application.Email);
            }

            _logger.LogInformation("Developer application submitted for {Email} as {Role} — user registered and ticket created",
                application.Email, application.Role);

            return (true, "Application submitted successfully! Your SilverDESK account has been created.", token);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error submitting developer application for {Email}", application.Email);
            return (false, "Unable to connect to the application service. Please try again later.", null);
        }
    }

    private static string ParseRegistrationError(string errorBody)
    {
        try
        {
            var error = JsonSerializer.Deserialize<JsonElement>(errorBody);
            if (error.TryGetProperty("message", out var message))
            {
                var msg = message.GetString() ?? "";
                if (msg.Contains("Username already exists", StringComparison.OrdinalIgnoreCase))
                    return "That username is already taken. Please choose a different one.";
                if (msg.Contains("Email already exists", StringComparison.OrdinalIgnoreCase))
                    return "An account with that email already exists.";
                if (msg.Contains("Password", StringComparison.OrdinalIgnoreCase))
                    return msg;
                return msg;
            }
        }
        catch { }

        return "Something went wrong creating your account. Please try again later.";
    }

    private static string FormatTicketBody(DeveloperApplication app)
    {
        var sb = new StringBuilder();
        sb.AppendLine("## Developer Program Application");
        sb.AppendLine();
        sb.AppendLine($"**Role:** {app.Role}");
        sb.AppendLine($"**Full Name:** {app.FullName}");
        sb.AppendLine($"**Email:** {app.Email}");
        sb.AppendLine($"**Desired Username:** {app.DesiredUsername}");
        sb.AppendLine($"**Timezone:** {app.Timezone}");
        sb.AppendLine();
        sb.AppendLine($"**Platforms:** {string.Join(", ", app.Platforms)}");
        sb.AppendLine();

        if (app.Role == ApplicationRole.Developer && !string.IsNullOrWhiteSpace(app.Skills))
        {
            sb.AppendLine("**Skills & Experience:**");
            sb.AppendLine(app.Skills);
            sb.AppendLine();
        }

        sb.AppendLine("**Motivation:**");
        sb.AppendLine(app.Motivation);

        return sb.ToString();
    }
}
