using System.ComponentModel;
using System.Text.Json;
using LazyBear.MCP.Services.ToolRegistry;
using ModelContextProtocol.Server;
using RestSharp;

namespace LazyBear.MCP.Services.GitLab;

public sealed class GitLabVersionTools(
    GitLabClientProvider provider,
    IConfiguration configuration,
    ToolRegistryService registry)
{
    private readonly string _token = configuration["GitLab:Token"] ?? string.Empty;
    private readonly string _baseUrl = configuration["GitLab:Url"] ?? string.Empty;
    private const string ModuleName = "GitLab";

    private bool TryCheckEnabled(string toolName, out string error)
    {
        if (!registry.IsToolEnabled(ModuleName, toolName))
        {
            error = $"Инструмент '{toolName}' модуля GitLab отключён в TUI.";
            return false;
        }
        error = string.Empty;
        return true;
    }

    private bool TryGetClient(out RestSharp.IRestClient client, out string error)
    {
        if (provider.InitializationError is not null)
        {
            client = null!;
            error = $"GitLab клиент не инициализирован. Детали: {provider.InitializationError}";
            return false;
        }

        var clientInstance = provider.GetClient();
        if (clientInstance is null)
        {
            client = null!;
            error = "GitLab клиент не создан.";
            return false;
        }

        client = clientInstance.RestClient;
        error = string.Empty;
        return true;
    }

    private string FormatResponseError(string toolName, RestResponse response, string? resource = null)
    {
        var resourcePart = string.IsNullOrWhiteSpace(resource) ? string.Empty : $", resource='{resource}'";
        var body = string.IsNullOrWhiteSpace(response.Content) ? "-" : response.Content;
        return $"Ошибка GitLab в tool '{toolName}'{resourcePart}: status={(int)response.StatusCode}, details={body}";
    }

    private string FormatException(string toolName, Exception exception, string? resource = null)
    {
        var resourcePart = string.IsNullOrWhiteSpace(resource) ? string.Empty : $", resource='{resource}'";
        return $"Ошибка GitLab в tool '{toolName}'{resourcePart}: {exception.GetType().Name}: {exception.Message}";
    }

    private static string GetVisibility(string visibility) => visibility switch
    {
        "public" => "Public",
        "internal" => "Internal",
        "private" => "Private",
        _ => visibility ?? "unknown"
    };

    private static string? GetNestedString(JsonElement element, params string[] path)
    {
        var current = element;
        foreach (var segment in path)
        {
            if (!current.TryGetProperty(segment, out current))
            {
                return null;
            }
        }
        return current.ValueKind == JsonValueKind.String ? current.GetString() : current.ToString();
    }

    /// <summary>
    /// Получить список тегов
    /// </summary>
    /// <param name="projectId">ID проекта</param>
    /// <param name="cancellationToken">Token отмены</param>
    [McpServerTool, Description("Получить список тегов проекта")]
    public async Task<string> ListVersions(
        [Description("ID проекта")] int projectId,
        CancellationToken cancellationToken = default)
    {
        if (!TryCheckEnabled("ListVersions", out var enabledError)) return enabledError;

        if (projectId <= 0)
        {
            return "ID проекта GitLab некорректно задан.";
        }

        if (!TryGetClient(out var client, out var error)) return error;

        try
        {
            var request = new RestRequest($"/projects/{projectId}/repository/tags", RestSharp.Method.Get);
            request.AddHeader("Accept", "application/json");
            request.AddHeader("PRIVATE-TOKEN", _token);
            request.AddQueryParameter("per_page", "30");

            var response = await client.ExecuteAsync(request, cancellationToken);

            if (!response.IsSuccessful || string.IsNullOrWhiteSpace(response.Content))
            {
                return FormatResponseError("list_versions", response, $"/projects/{projectId}/repository/tags");
            }

            using var document = JsonDocument.Parse(response.Content);
            var root = document.RootElement;

            if (!root.TryGetProperty("tags", out var tagsElement) || tagsElement.GetArrayLength() == 0)
            {
                return $"Тегов в проекте #{projectId} не найдено.";
            }

            var lines = new List<string>();
            foreach (var tag in tagsElement.EnumerateArray())
            {
                var name = GetNestedString(tag, "name") ?? "-";
                var commitSha = GetNestedString(tag, "commit", "sha") ?? "-";
                var commitMessage = GetNestedString(tag, "commit", "message") ?? "-";
                var tagType = GetNestedString(tag, "tag_type") ?? "unknown";

                lines.Add($"'{name}' (type={tagType}, sha={commitSha})\n  message: {commitMessage}");
            }

            return $"Тег версии проекта #{projectId} ({tagsElement.GetArrayLength()} шт.):\n{string.Join('\n', lines)}";
        }
        catch (Exception ex)
        {
            return FormatException("list_versions", ex);
        }
    }

    /// <summary>
    /// Создать тег
    /// </summary>
    /// <param name="projectId">ID проекта</param>
    /// <param name="name">Имя тега</param>
    /// <param name="description">Описание (опционально)</param>
    /// <param name="cancellationToken">Token отмены</param>
    [McpServerTool, Description("Создать тег версии")]
    public async Task<string> CreateVersion(
        [Description("ID проекта")] int projectId,
        [Description("Имя тега")] string name,
        [Description("Описание тега")] string? description = null,
        CancellationToken cancellationToken = default)
    {
        if (!TryCheckEnabled("CreateVersion", out var enabledError)) return enabledError;

        if (projectId <= 0)
        {
            return "ID проекта GitLab некорректно задан.";
        }

        if (string.IsNullOrWhiteSpace(name))
        {
            return "Имя тега GitLab не может быть пустым.";
        }

        if (!TryGetClient(out var client, out var error)) return error;

        try
        {
            var request = new RestRequest($"/projects/{projectId}/repository/tags", RestSharp.Method.Post);
            request.AddHeader("Accept", "application/json");
            request.AddHeader("PRIVATE-TOKEN", _token);
            request.AddHeader("Content-Type", "application/json");

            var jsonBody = new
            {
                name = name,
                description = description ?? string.Empty
            }.ToJson();
            request.AddJsonBody(jsonBody);

            var response = await client.ExecuteAsync(request, cancellationToken);

            if (!response.IsSuccessful || string.IsNullOrWhiteSpace(response.Content))
            {
                return FormatResponseError("create_version", response, $"/projects/{projectId}/repository/tags");
            }

            using var document = JsonDocument.Parse(response.Content);
            var root = document.RootElement;

            var tagName = GetNestedString(root, "name") ?? "-";
            var sha = GetNestedString(root, "commit", "sha") ?? "-";
            var refType = GetNestedString(root, "ref_type") ?? "-";

            return $"Тег версии создан в проекте #{projectId}:\n'{tagName}' (ref_type={refType}, sha={sha})";
        }
        catch (Exception ex)
        {
            return FormatException("create_version", ex);
        }
    }

    /// <summary>
    /// Удалить тег
    /// </summary>
    /// <param name="projectId">ID проекта</param>
    /// <param name="tagName">Имя тега</param>
    /// <param name="cancellationToken">Token отмены</param>
    [McpServerTool, Description("Удалить тег версии")]
    public async Task<string> DeleteVersion(
        [Description("ID проекта")] int projectId,
        [Description("Имя тега")] string tagName,
        CancellationToken cancellationToken = default)
    {
        if (!TryCheckEnabled("DeleteVersion", out var enabledError)) return enabledError;

        if (projectId <= 0)
        {
            return "ID проекта GitLab некорректно задан.";
        }

        if (string.IsNullOrWhiteSpace(tagName))
        {
            return "Имя тега GitLab не может быть пустым.";
        }

        if (!TryGetClient(out var client, out var error)) return error;

        try
        {
            var request = new RestRequest($"/projects/{projectId}/repository/tags/{tagName}", RestSharp.Method.Delete);
            request.AddHeader("Accept", "application/json");
            request.AddHeader("PRIVATE-TOKEN", _token);

            var response = await client.ExecuteAsync(request, cancellationToken);

            if (!response.IsSuccessful || string.IsNullOrWhiteSpace(response.Content))
            {
                return FormatResponseError("delete_version", response, $"/projects/{projectId}/repository/tags/{tagName}");
            }

            using var document = JsonDocument.Parse(response.Content);
            var root = document.RootElement;

            var deletedTag = GetNestedString(root, "name") ?? tagName;

            return $"Тег '{deletedTag}' успешно удалён из проекта #{projectId}.";
        }
        catch (Exception ex)
        {
            return FormatException("delete_version", ex);
        }
    }
}

internal static class JsonExtensions
{
    public static string ToJson(this object obj) =>
        System.Text.Json.JsonSerializer.Serialize(obj, new System.Text.Json.JsonSerializerOptions
        {
            WriteIndented = false
        });
}