using SilverLabs.Website.Models;
using SilverLabs.Website.Services;

namespace SilverLabs.Website.Endpoints;

public static class DeveloperEndpoints
{
    public static void MapDeveloperEndpoints(this WebApplication app)
    {
        var group = app.MapGroup("/api/developers");

        group.MapGet("/check-username/{username}", async (string username, DeveloperApplicationService service) =>
        {
            var available = await service.CheckUsernameAsync(username);
            if (available is null)
                return Results.Problem("Unable to verify username availability", statusCode: 503);
            return Results.Ok(new { available = available.Value });
        });

        group.MapPost("/apply", async (DeveloperApplication application, DeveloperApplicationService service) =>
        {
            var (success, message, token) = await service.SubmitApplicationAsync(application);
            return success
                ? Results.Ok(new { message, token })
                : Results.Problem(message, statusCode: 502);
        });

        group.MapPost("/approve/{ticketId}", async (
            string ticketId,
            DeveloperTicketParsingService ticketService,
            ProvisioningService provisioningService,
            HttpContext context,
            IConfiguration config) =>
        {
            var apiKey = context.Request.Headers["X-Api-Key"].FirstOrDefault();
            var expectedKey = config["AdminApiKey"];

            if (string.IsNullOrEmpty(expectedKey) || apiKey != expectedKey)
                return Results.Unauthorized();

            var ticket = await ticketService.FetchTicketAsync(ticketId);
            if (ticket is null)
                return Results.Problem("Failed to fetch ticket from SilverDESK", statusCode: 502);

            var description = ticket.Value.GetProperty("description").GetString() ?? "";
            var (fullName, email, desiredUsername) = ticketService.ParseApplicationFromDescription(description);

            if (string.IsNullOrEmpty(fullName) || string.IsNullOrEmpty(email) || string.IsNullOrEmpty(desiredUsername))
                return Results.Problem("Could not parse applicant details from ticket description", statusCode: 422);

            // Generate confirmation token instead of provisioning immediately
            var deployment = provisioningService.CreatePendingDeployment(desiredUsername, email, fullName, ticketId);

            var siteBase = config["SiteBaseUrl"] ?? "https://silverlabs.uk";
            var confirmUrl = $"{siteBase}/developers/confirm/{deployment.Token}";

            // Send ticket reply with confirmation link
            var replyContent = $"""
                Your application has been approved! To activate your accounts, please confirm your identity:

                **[Click here to activate your accounts]({confirmUrl})**

                You'll need to enter your SilverDESK password to complete the setup. This link expires in 48 hours.

                Once confirmed, the following accounts will be created for you:
                - **Email**: {desiredUsername}@silverlabs.uk
                - **Mattermost**: Team chat access
                - **Gitea**: Source code repository access
                """;

            var (replyOk, replyMsg) = await provisioningService.SendTicketReplyAsync(ticketId, replyContent);

            return Results.Ok(new
            {
                success = true,
                message = $"Confirmation link generated and sent via ticket reply. Reply status: {replyMsg}",
                confirmUrl
            });
        });

        // Token info endpoint for the confirmation page
        group.MapGet("/deployment-info/{token}", (string token, ProvisioningService provisioningService) =>
        {
            var deployment = provisioningService.GetPendingDeployment(token);
            if (deployment is null)
                return Results.NotFound(new { message = "Invalid or expired confirmation link" });

            return Results.Ok(new
            {
                username = deployment.Username,
                email = deployment.Email,
                fullName = deployment.FullName,
                expiresAt = deployment.ExpiresAt
            });
        });

        // Confirm deployment with password
        group.MapPost("/confirm-deployment", async (
            ConfirmDeploymentRequest request,
            ProvisioningService provisioningService) =>
        {
            var deployment = provisioningService.GetPendingDeployment(request.Token);
            if (deployment is null)
                return Results.NotFound(new { message = "Invalid or expired confirmation link" });

            // Validate credentials against SilverDESK
            var authenticated = await provisioningService.ValidateSilverDeskCredentialsAsync(
                deployment.Username, request.Password);

            if (!authenticated)
                return Results.Json(new { message = "Invalid password. Please enter your SilverDESK password." }, statusCode: 401);

            // Provision all services with the user's password
            var (success, message) = await provisioningService.ProvisionWithPasswordAsync(
                deployment.TicketId, deployment.Username, deployment.Email, deployment.FullName, request.Password);

            // Send follow-up ticket reply with results
            var resultContent = success
                ? $"""
                    Your accounts have been successfully provisioned:

                    {message}

                    You can now log in to all services with your SilverDESK credentials.
                    """
                : $"""
                    Account provisioning completed with some issues:

                    {message}

                    Please contact an administrator if you have trouble accessing any services.
                    """;

            await provisioningService.SendTicketReplyAsync(deployment.TicketId, resultContent, "close");

            // Remove the used token
            provisioningService.RemovePendingDeployment(request.Token);

            return Results.Ok(new { success, message });
        });

        // Password sync endpoint (called by SilverDESK on password reset)
        group.MapPost("/sync-password", async (
            SyncPasswordRequest request,
            ProvisioningService provisioningService,
            HttpContext context,
            IConfiguration config) =>
        {
            var apiKey = context.Request.Headers["X-Api-Key"].FirstOrDefault();
            var expectedKey = config["AdminApiKey"];

            if (string.IsNullOrEmpty(expectedKey) || apiKey != expectedKey)
                return Results.Unauthorized();

            var (success, message) = await provisioningService.SyncPasswordAsync(request.Username, request.NewPassword);

            return Results.Ok(new { success, message });
        });
    }
}

public record ConfirmDeploymentRequest(string Token, string Password);
public record SyncPasswordRequest(string Username, string NewPassword);
