using System.Collections.Generic;
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 GitLabIssueTools(
    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? GetNestedString(JsonElement element, params string[] path)
    {
        if (path.Length == 0) return null;
        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();
    }

    private static int GetNestedInt(JsonElement element, params string[] path)
    {
        var raw = GetNestedString(element, path);
        return int.TryParse(raw, out var value) ? value : 0;
    }

    private static string GetIid(int iid) => iid > 0 ? $"#{iid}" : "-";

    /// <summary>
    /// Получить список Issues
    /// </summary>
    /// <param name="projectId">ID проекта</param>
    /// <param name="issueState">Состояние issue (опционально)</param>
    /// <param name="cancellationToken">Token отмены</param>
    [McpServerTool, Description("Получить список Issues проекта")]
    public async Task<string> ListIssues(
        [Description("ID проекта")] int projectId,
        [Description("Состояние issue")] string? issueState = null,
        CancellationToken cancellationToken = default)
    {
        if (!TryCheckEnabled("ListIssues", 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}/issues", RestSharp.Method.Get);
            request.AddHeader("Accept", "application/json");
            request.AddHeader("PRIVATE-TOKEN", _token);
            request.AddQueryParameter("per_page", "30");

            if (!string.IsNullOrWhiteSpace(issueState))
            {
                request.AddQueryParameter("state", issueState);
            }

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

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

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

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

            var lines = new List<string>();
            foreach (var issue in issuesElement.EnumerateArray())
            {
                var iid = GetIid(GetNestedInt(issue, "iid"));
                var title = GetNestedString(issue, "title") ?? "-";
                var state = GetNestedString(issue, "state") ?? "-";
                var created_at = GetNestedString(issue, "created_at") ?? "-";
                var author = GetNestedString(issue, "author", "name") ?? "-";
                var labels = GetNestedString(issue, "labels") ?? "-";
                var labelsList = GetNestedString(issue, "labels") is string labelsStr && !string.IsNullOrWhiteSpace(labelsStr)
                    ? labelsStr.Split(',').Select(l => $"[{l.Trim()}]").ToArray() ?? new[] { labelsStr }
                    : Array.Empty<string>();

                lines.Add($"{iid} - {title} [{state}]\n  author: {author}\n  labels: {string.Join(", ", labelsList)}");
                lines.Add($"  created_at: {created_at}");
            }

            return $"Issues проекта #{projectId} ({issuesElement.GetArrayLength()} шт.):\n{string.Join(Environment.NewLine, lines)}";
        }
        catch (Exception ex)
        {
            return FormatException("list_issues", ex);
        }
    }

    /// <summary>
    /// Получить список Issues без фильтрации по state
    /// </summary>
    /// <param name="projectId">ID проекта</param>
    /// <param name="cancellationToken">Token отмены</param>
    [McpServerTool, Description("Получить список Issues проекта (без фильтра state)")]
    public async Task<string> ListIssuesSimple(
        [Description("ID проекта")] int projectId,
        CancellationToken cancellationToken = default)
    {
        if (!TryCheckEnabled("ListIssuesSimple", 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}/issues", 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_issues_simple", response, $"/projects/{projectId}/issues");
            }

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

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

            var lines = new List<string>();
            foreach (var issue in issuesElement.EnumerateArray())
            {
                var iid = GetIid(GetNestedInt(issue, "iid"));
                var title = GetNestedString(issue, "title") ?? "-";
                var state = GetNestedString(issue, "state") ?? "-";
                var author = GetNestedString(issue, "author", "name") ?? "-";
                var description = GetNestedString(issue, "description") ?? "-";

                lines.Add($"{iid} - {title} [{state}]\n  author: {author}\n  description: {description}");
            }

            return $"Issues проекта #{projectId} ({issuesElement.GetArrayLength()} шт.):\n{string.Join(Environment.NewLine, lines)}";
        }
        catch (Exception ex)
        {
            return FormatException("list_issues_simple", ex);
        }
    }

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

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

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

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

        try
        {
            var request = new RestRequest($"/projects/{projectId}/issues/{issueIid}", RestSharp.Method.Get);
            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("get_issue", response, $"/projects/{projectId}/issues/{issueIid}");
            }

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

            var iid = GetIid(GetNestedInt(root, "iid"));
            var title = GetNestedString(root, "title") ?? "-";
            var state = GetNestedString(root, "state") ?? "-";
            var author = GetNestedString(root, "author", "name") ?? "-";
            var created_at = GetNestedString(root, "created_at") ?? "-";
            var labels = GetNestedString(root, "labels") ?? "-";
            var description = GetNestedString(root, "description") ?? "-";
            var labelsList = GetNestedString(root, "labels") is string labelsStr && !string.IsNullOrWhiteSpace(labelsStr)
                ? labelsStr.Split(',').Select(l => $"[{l.Trim()}]").ToArray() ?? new[] { labelsStr }
                : Array.Empty<string>();

            return $"Issue #{iid} в проекте #{projectId}:\n{title} [{state}]\n  author: {author}\n  labels: {string.Join(", ", labelsList)}\n  created_at: {created_at}\n  description: {description}";
        }
        catch (Exception ex)
        {
            return FormatException("get_issue", ex, $"/projects/{projectId}/issues/{issueIid}");
        }
    }

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

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

        if (string.IsNullOrWhiteSpace(title))
        {
            return "Заголовок Issue GitLab не может быть пустым.";
        }

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

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

            var payload = new Dictionary<string, object?>
            {
                ["title"] = title,
                ["description"] = description ?? string.Empty
            };

            if (!string.IsNullOrWhiteSpace(labels))
            {
                payload["labels"] = labels;
            }

            if (assigneeId.HasValue)
            {
                payload["assignee_id"] = assigneeId.Value;
            }

            request.AddJsonBody(payload);

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

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

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

            var iid = GetIid(GetNestedInt(root, "iid"));
            var issueTitle = GetNestedString(root, "title") ?? "-";
            var issueState = GetNestedString(root, "state") ?? "-";

            return $"Issue успешно создан в проекте #{projectId}:\nID: {iid}\n{issueTitle} [{issueState}]";
        }
        catch (Exception ex)
        {
            return FormatException("create_issue", ex);
        }
    }

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

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

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

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

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

            var payload = new Dictionary<string, object?>();

            if (!string.IsNullOrWhiteSpace(subject))
            {
                payload["title"] = subject;
            }

            if (!string.IsNullOrWhiteSpace(description))
            {
                payload["description"] = description;
            }

            if (!string.IsNullOrWhiteSpace(labels))
            {
                payload["labels"] = labels;
            }

            if (!string.IsNullOrWhiteSpace(state))
            {
                payload["state_event"] = state;
            }

            request.AddJsonBody(payload);

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

            if (!response.IsSuccessful || string.IsNullOrWhiteSpace(response.Content))
            {
                return FormatResponseError("update_issue", response, $"/projects/{projectId}/issues/{issueIid}");
            }

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

            var iid = GetIid(GetNestedInt(root, "iid"));
            var issueTitle = GetNestedString(root, "title") ?? "-";
            var issueState = GetNestedString(root, "state") ?? "-";

            return $"Issue #{iid} ({issueTitle}) успешно обновлён в проекте #{projectId}.";
        }
        catch (Exception ex)
        {
            return FormatException("update_issue", ex, $"/projects/{projectId}/issues/{issueIid}");
        }
    }

    /// <summary>
    /// Закрыть Issue
    /// </summary>
    /// <param name="projectId">ID проекта</param>
    /// <param name="issueIid">ID Issue</param>
    /// <param name="cancellationToken">Token отмены</param>
    [McpServerTool, Description("Закрыть Issue")]
    public async Task<string> CloseIssue(
        [Description("ID проекта")] int projectId,
        [Description("ID Issue")] int issueIid,
        CancellationToken cancellationToken = default)
    {
        if (!TryCheckEnabled("CloseIssue", out var enabledError)) return enabledError;

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

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

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

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

            request.AddJsonBody(new { state_event = "close" });

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

            if (!response.IsSuccessful || string.IsNullOrWhiteSpace(response.Content))
            {
                return FormatResponseError("close_issue", response, $"/projects/{projectId}/issues/{issueIid}");
            }

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

            var issueTitle = GetNestedString(root, "title") ?? "-";

            return $"Issue #{issueIid} ({issueTitle}) успешно закрыт в проекте #{projectId}.";
        }
        catch (Exception ex)
        {
            return FormatException("close_issue", ex, $"/projects/{projectId}/issues/{issueIid}");
        }
    }

    /// <summary>
    /// Открыть Issue
    /// </summary>
    /// <param name="projectId">ID проекта</param>
    /// <param name="issueIid">ID Issue</param>
    /// <param name="cancellationToken">Token отмены</param>
    [McpServerTool, Description("Открыть Issue")]
    public async Task<string> OpenIssue(
        [Description("ID проекта")] int projectId,
        [Description("ID Issue")] int issueIid,
        CancellationToken cancellationToken = default)
    {
        if (!TryCheckEnabled("OpenIssue", out var enabledError)) return enabledError;

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

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

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

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

            request.AddJsonBody(new { state_event = "reopen" });

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

            if (!response.IsSuccessful || string.IsNullOrWhiteSpace(response.Content))
            {
                return FormatResponseError("open_issue", response, $"/projects/{projectId}/issues/{issueIid}");
            }

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

            var issueTitle = GetNestedString(root, "title") ?? "-";

            return $"Issue #{issueIid} ({issueTitle}) успешно открыт в проекте #{projectId}.";
        }
        catch (Exception ex)
        {
            return FormatException("open_issue", ex, $"/projects/{projectId}/issues/{issueIid}");
        }
    }

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

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

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

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

        try
        {
            var request = new RestRequest($"/projects/{projectId}/issues/{issueIid}/notes", 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_issue_notes", response, $"/projects/{projectId}/issues/{issueIid}/notes");
            }

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

            if (!root.TryGetProperty("notes", out var notesElement) || notesElement.GetArrayLength() == 0)
            {
                return $"Замечаний к Issue #{issueIid} не найдено.";
            }

            var lines = new List<string>();
            foreach (var note in notesElement.EnumerateArray())
            {
                var author = GetNestedString(note, "author", "name") ?? "-";
                var createdAt = GetNestedString(note, "created_at") ?? "-";
                var subject = GetNestedString(note, "subject") ?? "-";
                var body = GetNestedString(note, "body") ?? "-";

                lines.Add($"Author: {author}, Time: {createdAt}\n  Subject: {subject}\n  Body: {body}");
            }

            return $"Замечания к Issue #{issueIid} ({notesElement.GetArrayLength()} шт.):\n{string.Join(Environment.NewLine, lines)}";
        }
        catch (Exception ex)
        {
            return FormatException("list_issue_notes", ex);
        }
    }

    /// <summary>
    /// Добавить замечание к Issue
    /// </summary>
    /// <param name="projectId">ID проекта</param>
    /// <param name="issueIid">ID Issue</param>
    /// <param name="body">Текст замечания</param>
    /// <param name="subject">Заголовок замечания (опционально)</param>
    /// <param name="cancellationToken">Token отмены</param>
    [McpServerTool, Description("Добавить замечание к Issue")]
    public async Task<string> CreateIssueNote(
        [Description("ID проекта")] int projectId,
        [Description("ID Issue")] int issueIid,
        [Description("Текст замечания")] string body,
        [Description("Заголовок замечания")] string? subject = null,
        CancellationToken cancellationToken = default)
    {
        if (!TryCheckEnabled("CreateIssueNote", out var enabledError)) return enabledError;

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

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

        if (string.IsNullOrWhiteSpace(body))
        {
            return "Текст замечания GitLab не может быть пустым.";
        }

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

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

            request.AddJsonBody(new
            {
                body,
                subject = subject ?? string.Empty
            });

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

            if (!response.IsSuccessful || string.IsNullOrWhiteSpace(response.Content))
            {
                return FormatResponseError("create_issue_note", response, $"/projects/{projectId}/issues/{issueIid}/notes");
            }

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

            var noteId = GetNestedString(root, "id") ?? "-";
            var noteSubject = GetNestedString(root, "subject") ?? "-";
            var noteBody = GetNestedString(root, "body") ?? "-";

            return $"Замечание успешно добавлено к Issue #{issueIid}:\nID: #{noteId}\n{noteSubject}\n{noteBody}";
        }
        catch (Exception ex)
        {
            return FormatException("create_issue_note", ex);
        }
    }

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

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

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

        if (noteId <= 0)
        {
            return "ID замечания GitLab некорректно задан.";
        }

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

        try
        {
            var request = new RestRequest($"/projects/{projectId}/issues/{issueIid}/notes/{noteId}", 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_issue_note", response, $"/projects/{projectId}/issues/{issueIid}/notes/{noteId}");
            }

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

            var noteSubject = GetNestedString(root, "subject") ?? "-";

            return $"Замечание #{noteId} ({noteSubject}) успешно удалено из Issue #{issueIid}.";
        }
        catch (Exception ex)
        {
            return FormatException("delete_issue_note", ex, $"/projects/{projectId}/issues/{issueIid}/notes/{noteId}");
        }
    }
}