using System.Text.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WebClientTpos.Server.Infrastructure;
using WebClientTpos.Server.Models;

namespace WebClientTpos.Server.Controllers;

/// <summary>
/// EN: Order controller — proxies to OrderService for orders, POS checkout, and dashboard.
/// VI: Controller đơn hàng — proxy đến OrderService cho đơn hàng, POS thanh toán, dashboard.
/// </summary>
[ApiController]
[Route("api/bff")]
public class OrderController : ControllerBase
{
    private readonly HttpClient _order;
    private readonly HttpClient _merchant;

    public OrderController(IHttpClientFactory httpClientFactory)
    {
        _order = httpClientFactory.CreateClient("OrderService");
        _merchant = httpClientFactory.CreateClient("MerchantService");
    }

    /// <summary>
    /// EN: Get orders filtered by shop and date range (today/week/month).
    /// VI: Lấy đơn hàng theo shop và khoảng ngày (hôm nay/tuần/tháng).
    /// </summary>
    [HttpGet("orders")]
    public Task<IActionResult> GetOrders(
        [FromQuery] Guid? shopId = null,
        [FromQuery] string? filter = "today")
    {
        var qs = new List<string>();
        if (shopId.HasValue) qs.Add($"shopId={shopId}");

        // EN: Convert filter shorthand to fromDate/toDate for OrderService.
        //     "all" skips date filters entirely to return all historical orders.
        // VI: Chuyển đổi filter shorthand thành fromDate/toDate cho OrderService.
        //     "all" bỏ qua date filter để trả về toàn bộ đơn hàng.
        if (filter?.ToLower() != "all")
        {
            var now = DateTime.UtcNow;
            var (fromDate, toDate) = filter?.ToLower() switch
            {
                "week" => (now.Date.AddDays(-(int)now.DayOfWeek), now),
                "month" => (new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc), now),
                _ => (now.Date, now) // "today" or default
            };
            qs.Add($"fromDate={fromDate:O}");
            qs.Add($"toDate={toDate:O}");
        }

        var query = "?" + string.Join("&", qs);
        return _order.GetAsync($"/api/v1/orders{query}").ProxyAsync();
    }

    /// <summary>
    /// EN: Get full order detail with items.
    /// VI: Lấy chi tiết đơn hàng kèm items.
    /// </summary>
    [HttpGet("orders/{orderId:guid}")]
    public async Task<IActionResult> GetOrderDetail(Guid orderId, [FromQuery] Guid? shopId = null)
    {
        var qs = shopId.HasValue ? $"?shopId={shopId}" : "";
        var resp = await _order.GetAsync($"/api/v1/orders/{orderId}{qs}");
        if (!resp.IsSuccessStatusCode)
            return StatusCode((int)resp.StatusCode, await resp.Content.ReadAsStringAsync());

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

        // EN: Transform flat OrderDto {Id,ShopId,...,Items} into {Order:{...}, Items:[...]}
        // VI: Chuyển đổi OrderDto phẳng thành {Order:{...}, Items:[...]}
        var order = new Dictionary<string, object?>();
        JsonElement items = default;
        foreach (var prop in root.EnumerateObject())
        {
            if (prop.Name.Equals("items", StringComparison.OrdinalIgnoreCase))
            {
                items = prop.Value;
            }
            else
            {
                order[prop.Name] = System.Text.Json.JsonSerializer.Deserialize<object>(prop.Value.GetRawText());
            }
        }

        var itemsList = new List<object>();
        if (items.ValueKind == JsonValueKind.Array)
        {
            foreach (var item in items.EnumerateArray())
            {
                var dict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(item.GetRawText())!;
                // EN: Add subtotal field for frontend compatibility
                // VI: Thêm trường subtotal cho tương thích frontend
                if (item.TryGetProperty("quantity", out var qty) && item.TryGetProperty("unitPrice", out var up))
                {
                    dict["subtotal"] = qty.GetInt32() * up.GetDecimal();
                }
                itemsList.Add(dict);
            }
        }

        return Ok(new { order, items = itemsList });
    }

    /// <summary>
    /// EN: Cancel an order.
    /// VI: Hủy đơn hàng.
    /// </summary>
    [HttpPut("orders/{orderId:guid}/cancel")]
    public Task<IActionResult> CancelOrder(Guid orderId, [FromQuery] Guid? shopId = null)
    {
        var qs = shopId.HasValue ? $"?shopId={shopId}" : "";
        return _order.PostAsJsonAsync(
            $"/api/v1/orders/{orderId}/cancel{qs}",
            new { reason = "Cancelled from POS" }).ProxyAsync();
    }

    /// <summary>
    /// EN: Pay an order — forwards payment method and details to OrderService.
    /// VI: Thanh toán đơn hàng — chuyển tiếp phương thức thanh toán và chi tiết đến OrderService.
    /// </summary>
    [HttpPost("orders/{orderId:guid}/pay")]
    public Task<IActionResult> PayOrder(
        Guid orderId,
        [FromQuery] Guid? shopId = null,
        [FromBody] PayOrderBffRequest? request = null)
    {
        var qs = shopId.HasValue ? $"?shopId={shopId}" : "";
        var body = new
        {
            paymentMethod = request?.PaymentMethod ?? "cash",
            amountTendered = request?.AmountTendered,
            returnUrl = request?.ReturnUrl
        };
        return _order.PostAsJsonAsync($"/api/v1/orders/{orderId}/pay{qs}", body).ProxyAsync();
    }

    /// <summary>
    /// EN: Create a POS order. Enriches items with correct productType based on shop category.
    /// VI: Tạo đơn POS. Bổ sung productType chính xác cho items dựa trên loại shop.
    /// </summary>
    [HttpPost("pos/orders")]
    public async Task<IActionResult> CreatePosOrder([FromBody] JsonElement body)
    {
        // EN: Determine default productType from shop category
        // VI: Xác định productType mặc định từ loại shop
        var defaultProductType = "Physical";
        if (body.TryGetProperty("shopId", out var shopIdProp) && Guid.TryParse(shopIdProp.GetString(), out var shopId))
        {
            try
            {
                var shopResponse = await _merchant.GetAsync($"/api/v1/shops/{shopId}");
                if (shopResponse.IsSuccessStatusCode)
                {
                    var shopJson = await shopResponse.Content.ReadAsStringAsync();
                    using var shopDoc = JsonDocument.Parse(shopJson);
                    if (shopDoc.RootElement.TryGetProperty("category", out var categoryProp))
                    {
                        var category = categoryProp.GetString()?.ToLowerInvariant() ?? "";
                        defaultProductType = category switch
                        {
                            // EN: Cafe/Restaurant/Karaoke → PreparedFood (FnbStrategy, no inventory check)
                            // VI: Cafe/Restaurant/Karaoke → PreparedFood (FnbStrategy, không kiểm kho)
                            "cafe" or "restaurant" or "karaoke" => "PreparedFood",
                            // EN: Spa/Beauty → PreparedFood for POS walk-in sales (no appointment metadata needed)
                            //     Use "Service" only when item has appointment metadata (startTime, durationMinutes)
                            // VI: Spa/Beauty → PreparedFood cho POS bán trực tiếp (không cần metadata đặt lịch)
                            //     Chỉ dùng "Service" khi item có metadata đặt lịch
                            "spa" or "beauty" => "PreparedFood",
                            _ => "Physical"
                        };
                    }
                }
            }
            catch { /* fallback to Physical */ }
        }

        // EN: Rewrite items with correct productType based on shop category and item metadata
        // VI: Ghi lại items với productType đúng dựa trên loại shop và metadata của item
        using var doc = JsonDocument.Parse(body.GetRawText());
        var root = doc.RootElement;
        var options = new JsonWriterOptions { Indented = false };
        using var stream = new MemoryStream();
        using (var writer = new Utf8JsonWriter(stream, options))
        {
            writer.WriteStartObject();
            foreach (var prop in root.EnumerateObject())
            {
                if (prop.Name == "items" && prop.Value.ValueKind == JsonValueKind.Array)
                {
                    writer.WriteStartArray("items");
                    foreach (var item in prop.Value.EnumerateArray())
                    {
                        // EN: If item has appointment metadata, use "Service" type; otherwise use shop default
                        // VI: Nếu item có metadata đặt lịch, dùng "Service"; còn lại dùng default của shop
                        var itemType = defaultProductType;
                        if (item.TryGetProperty("metadata", out var meta) && meta.ValueKind == JsonValueKind.String)
                        {
                            try
                            {
                                using var metaDoc = JsonDocument.Parse(meta.GetString()!);
                                if (metaDoc.RootElement.TryGetProperty("startTime", out _) &&
                                    metaDoc.RootElement.TryGetProperty("durationMinutes", out _))
                                {
                                    itemType = "Service";
                                }
                            }
                            catch { /* not valid metadata JSON, use default */ }
                        }

                        writer.WriteStartObject();
                        foreach (var itemProp in item.EnumerateObject())
                        {
                            if (itemProp.Name == "productType")
                            {
                                writer.WriteString("productType", itemType);
                            }
                            else
                            {
                                itemProp.WriteTo(writer);
                            }
                        }
                        if (!item.TryGetProperty("productType", out _))
                        {
                            writer.WriteString("productType", itemType);
                        }
                        // EN: Default all PreparedFood items to track inventory for auto-deduction
                        // VI: Mặc định tất cả PreparedFood items theo dõi tồn kho để tự động trừ kho
                        if (!item.TryGetProperty("trackInventory", out _))
                        {
                            writer.WriteBoolean("trackInventory", true);
                        }
                        writer.WriteEndObject();
                    }
                    writer.WriteEndArray();
                }
                else
                {
                    prop.WriteTo(writer);
                }
            }
            writer.WriteEndObject();
        }

        var enrichedBody = JsonDocument.Parse(stream.ToArray()).RootElement;
        return await _order.PostAsJsonAsync("/api/v1/orders", enrichedBody).ProxyAsync();
    }

    /// <summary>
    /// EN: Get active (unpaid) orders grouped by table for a shop.
    /// VI: Lấy orders chưa thanh toán nhóm theo bàn cho shop.
    /// </summary>
    [HttpGet("orders/active-by-table")]
    public Task<IActionResult> GetActiveTableOrders([FromQuery] Guid? shopId = null)
    {
        var qs = shopId.HasValue ? $"?shopId={shopId}" : "";
        return _order.GetAsync($"/api/v1/orders/active-by-table{qs}").ProxyAsync();
    }

    /// <summary>
    /// EN: Get POS dashboard data — daily revenue, order count, popular items.
    /// VI: Lấy dữ liệu dashboard POS — doanh thu ngày, số đơn, món bán chạy.
    /// </summary>
    [HttpGet("pos/dashboard")]
    public Task<IActionResult> GetPosDashboard([FromQuery] Guid? shopId = null, [FromQuery] string? period = "today")
    {
        var qsList = new List<string>();
        if (shopId.HasValue) qsList.Add($"shopId={shopId}");
        if (!string.IsNullOrEmpty(period)) qsList.Add($"period={period}");
        var qs = qsList.Any() ? "?" + string.Join("&", qsList) : "";
        return _order.GetAsync($"/api/v1/orders/dashboard{qs}").ProxyAsync();
    }
}
