using System.Text;
using System.Text.Json;

namespace WebClientTpos.Server.AiChat;

/// <summary>
/// EN: Executes MCP tool calls by routing them to the appropriate microservice HTTP endpoints.
///     Maps tool names to CatalogService, InventoryService, FnbEngine, and OrderService.
/// VI: Thuc thi cac MCP tool call bang cach dinh tuyen den endpoint HTTP microservice tuong ung.
///     Map ten tool den CatalogService, InventoryService, FnbEngine, va OrderService.
/// </summary>
public class McpToolExecutor
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly ILogger<McpToolExecutor> _logger;

    public McpToolExecutor(IHttpClientFactory httpClientFactory, ILogger<McpToolExecutor> logger)
    {
        _httpClientFactory = httpClientFactory;
        _logger = logger;
    }

    /// <summary>
    /// EN: Execute a single tool call by name, routing to the correct microservice endpoint.
    /// VI: Thuc thi mot tool call theo ten, dinh tuyen den endpoint microservice dung.
    /// </summary>
    public async Task<string> ExecuteToolAsync(string toolName, string argumentsJson, CancellationToken ct = default)
    {
        _logger.LogInformation("EN: Executing MCP tool '{ToolName}' with args: {Args}.",
                               toolName, argumentsJson);

        try
        {
            var args = JsonDocument.Parse(argumentsJson).RootElement;

            return toolName switch
            {
                "list_products" => await ListProductsAsync(args, ct),
                "create_product" => await CreateProductAsync(args, ct),
                "update_product" => await UpdateProductAsync(args, ct),
                "delete_product" => await DeleteProductAsync(args, ct),
                "check_inventory" => await CheckInventoryAsync(args, ct),
                "record_intake" => await RecordIntakeAsync(args, ct),
                "record_usage" => await RecordUsageAsync(args, ct),
                "low_stock_alerts" => await LowStockAlertsAsync(args, ct),
                "list_recipes" => await ListRecipesAsync(args, ct),
                "create_recipe" => await CreateRecipeAsync(args, ct),
                "popular_items" => await PopularItemsAsync(args, ct),
                "cost_analysis" => await CostAnalysisAsync(args, ct),
                _ => JsonSerializer.Serialize(new { error = $"Unknown tool: {toolName}" })
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "EN: Failed to execute MCP tool '{ToolName}'.", toolName);
            return JsonSerializer.Serialize(new { error = ex.Message });
        }
    }

    // ═══════════════════════════════════════════════════════════════════════════════
    // EN: Catalog tools — CatalogService
    // VI: Cac tool danh muc — CatalogService
    // ═══════════════════════════════════════════════════════════════════════════════

    /// <summary>
    /// EN: List products — GET CatalogService /api/v1/products?shopId=&categoryId=&isActive=&page=&pageSize=
    /// VI: Liet ke san pham — GET CatalogService /api/v1/products
    /// </summary>
    private async Task<string> ListProductsAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("CatalogService");
        var qs = BuildQueryString(args, "shopId", "categoryId", "isActive", "page", "pageSize");
        var response = await client.GetAsync($"/api/v1/products{qs}", ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    /// <summary>
    /// EN: Create product — POST CatalogService /api/v1/products
    /// VI: Tao san pham — POST CatalogService /api/v1/products
    /// </summary>
    private async Task<string> CreateProductAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("CatalogService");
        var body = new StringContent(args.GetRawText(), Encoding.UTF8, "application/json");
        var response = await client.PostAsync("/api/v1/products", body, ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    /// <summary>
    /// EN: Update product — PUT CatalogService /api/v1/products/{productId}
    /// VI: Cap nhat san pham — PUT CatalogService /api/v1/products/{productId}
    /// </summary>
    private async Task<string> UpdateProductAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("CatalogService");
        var productId = args.GetProperty("productId").GetString();
        var body = new StringContent(args.GetRawText(), Encoding.UTF8, "application/json");
        var response = await client.PutAsync($"/api/v1/products/{productId}", body, ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    /// <summary>
    /// EN: Delete product — DELETE CatalogService /api/v1/products/{productId}
    /// VI: Xoa san pham — DELETE CatalogService /api/v1/products/{productId}
    /// </summary>
    private async Task<string> DeleteProductAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("CatalogService");
        var productId = args.GetProperty("productId").GetString();
        var response = await client.DeleteAsync($"/api/v1/products/{productId}", ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    // ═══════════════════════════════════════════════════════════════════════════════
    // EN: Inventory tools — InventoryService
    // VI: Cac tool ton kho — InventoryService
    // ═══════════════════════════════════════════════════════════════════════════════

    /// <summary>
    /// EN: Check inventory — GET InventoryService /api/v1/inventory?shopId=&skip=&take=
    /// VI: Kiem tra ton kho — GET InventoryService /api/v1/inventory
    /// </summary>
    private async Task<string> CheckInventoryAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("InventoryService");
        var qs = BuildQueryString(args, "shopId", "skip", "take");
        var response = await client.GetAsync($"/api/v1/inventory{qs}", ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    /// <summary>
    /// EN: Record stock-in — POST InventoryService /api/v1/inventory/stock-in
    /// VI: Ghi nhan nhap kho — POST InventoryService /api/v1/inventory/stock-in
    /// </summary>
    private async Task<string> RecordIntakeAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("InventoryService");
        var body = new StringContent(args.GetRawText(), Encoding.UTF8, "application/json");
        var response = await client.PostAsync("/api/v1/inventory/stock-in", body, ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    /// <summary>
    /// EN: Record stock-out — POST InventoryService /api/v1/inventory/stock-out
    /// VI: Ghi nhan xuat kho — POST InventoryService /api/v1/inventory/stock-out
    /// </summary>
    private async Task<string> RecordUsageAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("InventoryService");
        var body = new StringContent(args.GetRawText(), Encoding.UTF8, "application/json");
        var response = await client.PostAsync("/api/v1/inventory/stock-out", body, ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    /// <summary>
    /// EN: Low stock alerts — GET InventoryService /api/v1/inventory/low-stock?shopId=&threshold=
    /// VI: Canh bao ton kho thap — GET InventoryService /api/v1/inventory/low-stock
    /// </summary>
    private async Task<string> LowStockAlertsAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("InventoryService");
        var qs = BuildQueryString(args, "shopId", "threshold");
        var response = await client.GetAsync($"/api/v1/inventory/low-stock{qs}", ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    // ═══════════════════════════════════════════════════════════════════════════════
    // EN: FnB Engine tools — FnbEngine
    // VI: Cac tool FnB Engine — FnbEngine
    // ═══════════════════════════════════════════════════════════════════════════════

    /// <summary>
    /// EN: List recipes — GET FnbEngine /api/v1/kitchen/recipes?shopId=
    /// VI: Liet ke cong thuc — GET FnbEngine /api/v1/kitchen/recipes
    /// </summary>
    private async Task<string> ListRecipesAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("FnbEngine");
        var qs = BuildQueryString(args, "shopId");
        var response = await client.GetAsync($"/api/v1/kitchen/recipes{qs}", ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    /// <summary>
    /// EN: Create recipe — POST FnbEngine /api/v1/kitchen/recipes
    /// VI: Tao cong thuc — POST FnbEngine /api/v1/kitchen/recipes
    /// </summary>
    private async Task<string> CreateRecipeAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("FnbEngine");
        var body = new StringContent(args.GetRawText(), Encoding.UTF8, "application/json");
        var response = await client.PostAsync("/api/v1/kitchen/recipes", body, ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    // ═══════════════════════════════════════════════════════════════════════════════
    // EN: Analytics tools — OrderService, InventoryService
    // VI: Cac tool phan tich — OrderService, InventoryService
    // ═══════════════════════════════════════════════════════════════════════════════

    /// <summary>
    /// EN: Popular items — GET OrderService /api/v1/orders/dashboard?shopId=&period=
    /// VI: San pham pho bien — GET OrderService /api/v1/orders/dashboard
    /// </summary>
    private async Task<string> PopularItemsAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("OrderService");
        var qs = BuildQueryString(args, "shopId", "period");
        var response = await client.GetAsync($"/api/v1/orders/dashboard{qs}", ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    /// <summary>
    /// EN: Cost analysis — GET InventoryService /api/v1/inventory/cost-analysis?shopId=
    /// VI: Phan tich chi phi — GET InventoryService /api/v1/inventory/cost-analysis
    /// </summary>
    private async Task<string> CostAnalysisAsync(JsonElement args, CancellationToken ct)
    {
        var client = GetClient("InventoryService");
        var qs = BuildQueryString(args, "shopId");
        var response = await client.GetAsync($"/api/v1/inventory/cost-analysis{qs}", ct);
        return await response.Content.ReadAsStringAsync(ct);
    }

    // ═══════════════════════════════════════════════════════════════════════════════
    // EN: Helper methods
    // VI: Cac phuong thuc tro giup
    // ═══════════════════════════════════════════════════════════════════════════════

    /// <summary>
    /// EN: Get a named HttpClient from the factory.
    /// VI: Lay HttpClient theo ten tu factory.
    /// </summary>
    private HttpClient GetClient(string name) => _httpClientFactory.CreateClient(name);

    /// <summary>
    /// EN: Build a query string from JSON element properties. Only includes non-null values.
    /// VI: Xay dung query string tu cac thuoc tinh JSON element. Chi bao gom cac gia tri khong null.
    /// </summary>
    private static string BuildQueryString(JsonElement args, params string[] paramNames)
    {
        var parts = new List<string>();

        foreach (var name in paramNames)
        {
            if (args.TryGetProperty(name, out var value) && value.ValueKind != JsonValueKind.Null)
            {
                var stringValue = value.ValueKind switch
                {
                    JsonValueKind.True => "true",
                    JsonValueKind.False => "false",
                    JsonValueKind.Number => value.GetRawText(),
                    JsonValueKind.String => Uri.EscapeDataString(value.GetString()!),
                    _ => value.GetRawText()
                };
                parts.Add($"{name}={stringValue}");
            }
        }

        return parts.Count > 0 ? "?" + string.Join("&", parts) : "";
    }
}
