using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Mvc;

namespace WebClientTpos.Server.Controllers;

/// <summary>
/// EN: Public menu controller — serves shop info and menu data for customer QR code scanning.
///     These endpoints do NOT require authentication.
/// VI: Controller menu công khai — phục vụ thông tin shop và menu cho khách hàng quét mã QR.
///     Các endpoint này KHÔNG yêu cầu xác thực.
/// </summary>
[ApiController]
[Route("api/public")]
public class PublicMenuController : ControllerBase
{
    private readonly HttpClient _merchant;
    private readonly HttpClient _catalog;
    private static readonly JsonSerializerOptions JsonOpts = new()
    {
        PropertyNameCaseInsensitive = true,
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
    };

    private readonly ILogger<PublicMenuController> _logger;

    public PublicMenuController(IHttpClientFactory httpClientFactory, ILogger<PublicMenuController> logger)
    {
        _merchant = httpClientFactory.CreateClient("MerchantService");
        _catalog = httpClientFactory.CreateClient("CatalogService");
        _logger = logger;
    }

    /// <summary>
    /// EN: Get public shop info (name, address, logo, phone) — no auth required.
    /// VI: Lấy thông tin shop công khai (tên, địa chỉ, logo, SĐT) — không cần xác thực.
    /// </summary>
    [HttpGet("shops/{shopId:guid}")]
    public async Task<IActionResult> GetPublicShopInfo(Guid shopId, CancellationToken cancellationToken)
    {
        try
        {
            var resp = await _merchant.GetAsync($"/api/v1/shops/{shopId}", cancellationToken);
            if (!resp.IsSuccessStatusCode)
                return NotFound(new { success = false, error = new { code = "SHOP_NOT_FOUND", message = "Shop not found / Không tìm thấy cửa hàng" } });

            var json = await resp.Content.ReadAsStringAsync();
            using var doc = JsonDocument.Parse(json);
            var root = doc.RootElement;

            // EN: Extract only public-safe fields from shop data
            // VI: Chỉ trích xuất các trường an toàn công khai từ dữ liệu shop
            var shopData = root.ValueKind == JsonValueKind.Object && root.TryGetProperty("data", out var data)
                ? data : root;

            var publicInfo = new
            {
                id = shopId,
                name = shopData.TryGetProperty("name", out var n) ? n.GetString() : "Shop",
                address = shopData.TryGetProperty("address", out var a) ? a.GetString() : null as string,
                logoUrl = shopData.TryGetProperty("logoUrl", out var l) ? l.GetString() :
                         shopData.TryGetProperty("logo", out var l2) ? l2.GetString() : null as string,
                phone = shopData.TryGetProperty("phone", out var p) ? p.GetString() : null as string,
                description = shopData.TryGetProperty("description", out var d) ? d.GetString() : null as string
            };

            return Ok(new { success = true, data = publicInfo });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "EN: Failed to load public shop info for {ShopId} / VI: Không thể tải thông tin shop công khai cho {ShopId}", shopId, shopId);
            return StatusCode(500, new { success = false, error = new { code = "INTERNAL_ERROR", message = "Failed to load shop info / Không thể tải thông tin shop" } });
        }
    }

    /// <summary>
    /// EN: Get public menu — categories with products, sorted by display order. No auth required.
    /// VI: Lấy menu công khai — danh mục kèm sản phẩm, sắp xếp theo thứ tự hiển thị. Không cần xác thực.
    /// </summary>
    [HttpGet("shops/{shopId:guid}/menu")]
    public async Task<IActionResult> GetPublicMenu(Guid shopId, CancellationToken cancellationToken)
    {
        try
        {
            // EN: Fetch categories and products in parallel
            // VI: Lấy danh mục và sản phẩm song song
            var categoriesTask = _catalog.GetAsync($"/api/v1/shops/{shopId}/categories", cancellationToken);
            var productsTask = _catalog.GetAsync($"/api/v1/shops/{shopId}/products?isActive=true&pageSize=500", cancellationToken);

            await Task.WhenAll(categoriesTask, productsTask);

            var categoriesResp = await categoriesTask;
            var productsResp = await productsTask;

            // EN: Parse categories
            // VI: Phân tích danh mục
            var categories = new List<CategoryDto>();
            if (categoriesResp.IsSuccessStatusCode)
            {
                var catJson = await categoriesResp.Content.ReadAsStringAsync();
                categories = ParseList<CategoryDto>(catJson);
            }

            // EN: Parse products
            // VI: Phân tích sản phẩm
            var products = new List<ProductDto>();
            if (productsResp.IsSuccessStatusCode)
            {
                var prodJson = await productsResp.Content.ReadAsStringAsync();
                products = ParseList<ProductDto>(prodJson);
            }

            // EN: Group products by category and build menu structure
            // VI: Nhóm sản phẩm theo danh mục và xây dựng cấu trúc menu
            var productsByCategory = products.GroupBy(p => p.CategoryId).ToDictionary(g => g.Key, g => g.ToList());

            var menuCategories = categories
                .OrderBy(c => c.DisplayOrder)
                .Select(c => new
                {
                    id = c.Id,
                    name = c.Name,
                    description = c.Description,
                    displayOrder = c.DisplayOrder,
                    items = productsByCategory.GetValueOrDefault(c.Id, [])
                        .Select(p => new
                        {
                            id = p.Id,
                            name = p.Name,
                            description = p.Description,
                            price = p.Price,
                            imageUrl = p.ImageUrl,
                            isAvailable = p.IsActive
                        }).ToList()
                })
                .Where(c => c.items.Count > 0)
                .ToList();

            // EN: Add an "Uncategorized" group for products without categories
            // VI: Thêm nhóm "Chưa phân loại" cho sản phẩm không có danh mục
            var uncategorized = products.Where(p => p.CategoryId == Guid.Empty || !categories.Any(c => c.Id == p.CategoryId)).ToList();
            if (uncategorized.Count > 0)
            {
                menuCategories.Add(new
                {
                    id = Guid.Empty,
                    name = "Khác",
                    description = (string?)null,
                    displayOrder = 9999,
                    items = uncategorized.Select(p => new
                    {
                        id = p.Id,
                        name = p.Name,
                        description = p.Description,
                        price = p.Price,
                        imageUrl = p.ImageUrl,
                        isAvailable = p.IsActive
                    }).ToList()
                });
            }

            return Ok(new { success = true, data = menuCategories });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "EN: Failed to load public menu for {ShopId} / VI: Không thể tải menu công khai cho {ShopId}", shopId, shopId);
            return StatusCode(500, new { success = false, error = new { code = "INTERNAL_ERROR", message = "Failed to load menu / Không thể tải menu" } });
        }
    }

    // EN: Parse a list from various API response formats
    // VI: Phân tích list từ các định dạng response API khác nhau
    private static List<T> ParseList<T>(string json)
    {
        if (string.IsNullOrWhiteSpace(json)) return [];
        try
        {
            using var doc = JsonDocument.Parse(json);
            var root = doc.RootElement;

            if (root.ValueKind == JsonValueKind.Array)
                return JsonSerializer.Deserialize<List<T>>(json, JsonOpts) ?? [];

            if (root.TryGetProperty("items", out var items) && items.ValueKind == JsonValueKind.Array)
                return JsonSerializer.Deserialize<List<T>>(items.GetRawText(), JsonOpts) ?? [];

            if (root.TryGetProperty("data", out var data))
            {
                if (data.ValueKind == JsonValueKind.Array)
                    return JsonSerializer.Deserialize<List<T>>(data.GetRawText(), JsonOpts) ?? [];
                if (data.ValueKind == JsonValueKind.Object && data.TryGetProperty("items", out var dataItems) && dataItems.ValueKind == JsonValueKind.Array)
                    return JsonSerializer.Deserialize<List<T>>(dataItems.GetRawText(), JsonOpts) ?? [];
            }

            return [];
        }
        catch { return []; }
    }

    private record CategoryDto
    {
        public Guid Id { get; init; }
        public string Name { get; init; } = "";
        public string? Description { get; init; }
        public int DisplayOrder { get; init; }
    }

    private record ProductDto
    {
        public Guid Id { get; init; }
        public string Name { get; init; } = "";
        public string? Description { get; init; }
        public decimal Price { get; init; }
        public string? ImageUrl { get; init; }
        public bool IsActive { get; init; } = true;
        public Guid CategoryId { get; init; }
    }
}
