using System.Text.Json.Serialization;
using Knot.Contracts.Conversations.Abstractions;
using Knot.Contracts.Settings.Application.Abstractions;
using Knot.Contracts.Settings.Application.DTOs;
using Knot.Modules.Admin.Application.Admin.Commands;
using Knot.Modules.Admin.Application.Admin.Commands.CreateUser;
using Knot.Modules.Admin.Application.Admin.Commands.TestKlipy;
using Knot.Modules.Admin.Application.Admin.Queries;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;

namespace Knot.Modules.Admin.Presentation.Endpoints;

public record KlipyTestDto(
    [property: JsonPropertyName("apiKey")] string ApiKey,
    [property: JsonPropertyName("appName")] string AppName);
public record ResetPasswordRequest(string NewPassword);

public static class AdminEndpoints
{
    public static void MapAdminEndpoints(this WebApplication app)
    {
        var group = app.MapGroup("api/admin"); // Middleware handles auth

        group.MapGet("settings", async (ISender sender, CancellationToken ct) =>
        {
            var result = await sender.Send(new GetSettingsQuery(), ct);
            return Results.Ok(result.Value);
        });

        group.MapPut("settings", async ([FromBody] SystemSettingsDto settings, ISender sender, CancellationToken ct) =>
        {
            var result = await sender.Send(new UpdateSettingsCommand(settings), ct);
            return Results.Ok(result.Value);
        });

        group.MapPost("settings/test-klipy", async ([FromBody] KlipyTestDto dto, ISender sender, CancellationToken ct) =>
        {
            Console.WriteLine($"[Admin] TestKlipy received: ApiKey={(string.IsNullOrEmpty(dto.ApiKey) ? "EMPTY" : "present")}, AppName={(string.IsNullOrEmpty(dto.AppName) ? "EMPTY" : dto.AppName)}");

            if (string.IsNullOrEmpty(dto.ApiKey) || string.IsNullOrEmpty(dto.AppName))
            {
                Console.WriteLine($"[Admin] TestKlipy: Missing required fields - ApiKey={dto?.ApiKey}, AppName={dto?.AppName}");
                return Results.BadRequest(new { error = "ApiKey and AppName are required" });
            }

            var result = await sender.Send(new TestKlipyConnectionCommand(dto.ApiKey, dto.AppName), ct);
            Console.WriteLine($"[Admin] TestKlipy result: IsSuccess={result.IsSuccess}, Error={result.Error?.Description}");
            return result.IsSuccess ? Results.Ok(new { success = true }) : Results.BadRequest(new { error = result.Error.Description });
        });

        group.MapGet("dashboard", async (ISender sender, CancellationToken ct) =>
        {
            var result = await sender.Send(new GetDashboardStatsQuery(), ct);
            return Results.Ok(result.Value);
        });

        group.MapPost("users", async ([FromBody] CreateUserCommand command, ISender sender, CancellationToken ct) =>
        {
            var result = await sender.Send(command, ct);
            return result.IsSuccess ? Results.Created($"/api/admin/users/{result.Value.Id}", result.Value) : Results.BadRequest(new { error = result.Error.Description });
        });

        group.MapPost("users/{userId:guid}/reset-password", async ([FromRoute] Guid userId, [FromBody] ResetPasswordRequest dto, ISender sender, CancellationToken ct) =>
        {
            var result = await sender.Send(new ResetUserPasswordCommand(userId, dto.NewPassword), ct);
            if (result.IsFailure)
            {
                if (result.Error.Code == "User.NotFound") return Results.NotFound(new { error = "User not found" });
                return Results.BadRequest(new { error = result.Error.Description });
            }
            return Results.Ok(result.Value);
        });

        group.MapPost("users/{userId:guid}/ban", async ([FromRoute] Guid userId, ISender sender, CancellationToken ct) =>
        {
            var result = await sender.Send(new BanUserCommand(userId), ct);
            return result.IsSuccess ? Results.Ok() : Results.BadRequest(new { error = result.Error.Description });
        });

        group.MapPost("users/{userId:guid}/unban", async ([FromRoute] Guid userId, ISender sender, CancellationToken ct) =>
        {
            var result = await sender.Send(new UnbanUserCommand(userId), ct);
            return result.IsSuccess ? Results.Ok() : Results.BadRequest(new { error = result.Error.Description });
        });

        group.MapGet("users", async (ISender sender, [FromQuery] string? query, CancellationToken ct = default) =>
        {
            // При пустом или отсутствующем query возвращаем всех пользователей
            var searchQuery = string.IsNullOrWhiteSpace(query) ? "" : query;
            try
            {
                var result = await sender.Send(new SearchUsersQuery(searchQuery), ct);
                if (!result.IsSuccess)
                {
                    Console.WriteLine($"[Admin] SearchUsers error: {result.Error.Code} - {result.Error.Description}");
                    return Results.BadRequest(new { error = result.Error.Description });
                }
                return Results.Ok(result.Value);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[Admin] SearchUsers exception: {ex}");
                return Results.BadRequest(new { error = ex.Message });
            }
        });

        group.MapGet("users/{id:guid}", async ([FromRoute] Guid id, ISender sender, CancellationToken ct) =>
        {
            var result = await sender.Send(new GetUserDetailsQuery(id), ct);
            return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound("User not found");
        });

        group.MapDelete("users/{userId:guid}", async ([FromRoute] Guid userId, IUserDeleterService userDeleter, CancellationToken ct) =>
        {
            var result = await userDeleter.DeleteUserAsync(userId, ct);
            return result.IsSuccess ? Results.Ok() : Results.BadRequest(new { error = result.Error.Description });
        });

        group.MapGet("clean/dry-run", async (ISender sender, CancellationToken ct) =>
        {
            var result = await sender.Send(new CleanDryRunQuery(), ct);
            if (!result.IsSuccess)
            {
                Console.WriteLine($"[Admin] Cleanup Dry Run Error: {result.Error.Description}");
                return Results.BadRequest(new { error = result.Error.Description });
            }
            return Results.Ok(result.Value);
        });

        group.MapPost("clean/run", async (ISender sender, CancellationToken ct) =>
        {
            var result = await sender.Send(new CleanRunCommand(), ct);
            if (!result.IsSuccess)
            {
                Console.WriteLine($"[Admin] Cleanup Run Error: {result.Error.Description}");
                return Results.BadRequest(new { error = result.Error.Description });
            }
            return Results.Ok(result.Value);
        });

        group.MapGet("timezones", () =>
        {
            // Получаем все системные часовые пояса и формируем удобный для фронтенда формат
            var zones = TimeZoneInfo.GetSystemTimeZones()
                .Select(tz => new
                {
                    id = tz.Id,
                    displayName = tz.DisplayName,
                    standardName = tz.StandardName,
                    offsetMinutes = tz.BaseUtcOffset.TotalMinutes,
                    offsetString = (tz.BaseUtcOffset >= TimeSpan.Zero ? "+" : "-") + tz.BaseUtcOffset.ToString(@"hh\:mm")
                })
                .OrderBy(tz => tz.offsetMinutes);

            return Results.Ok(zones);
        });
    }
}
