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

namespace WebClientTpos.Server.Controllers;

/// <summary>
/// EN: Financial controller — proxies to WalletService (wallets/transactions) and PromotionService (campaigns).
/// VI: Controller tài chính — proxy đến WalletService (ví/giao dịch) và PromotionService (chiến dịch).
/// </summary>
[ApiController]
[Route("api/bff")]
public class FinancialController : ControllerBase
{
    private readonly HttpClient _wallet;
    private readonly HttpClient _promotion;

    public FinancialController(IHttpClientFactory httpClientFactory)
    {
        _wallet = httpClientFactory.CreateClient("WalletService");
        _promotion = httpClientFactory.CreateClient("PromotionService");
    }

    /// <summary>
    /// EN: Extract userId from JWT — reads httpOnly session cookie first, then Authorization header (fallback).
    /// VI: Trích xuất userId từ JWT — đọc httpOnly session cookie trước, rồi Authorization header (fallback).
    /// </summary>
    private Guid? GetUserIdFromToken()
    {
        // EN: (1) Prefer httpOnly session cookie (BFF auth pattern).
        // VI: (1) Ưu tiên httpOnly session cookie (BFF auth pattern).
        string? token = null;
        if (Request.Cookies.TryGetValue("bff_session", out var sessionToken) && !string.IsNullOrEmpty(sessionToken))
        {
            token = sessionToken;
        }
        else
        {
            // EN: (2) Legacy fallback — Authorization header.
            // VI: (2) Fallback cũ — Authorization header.
            var authHeader = Request.Headers["Authorization"].FirstOrDefault();
            if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ")) return null;
            token = authHeader["Bearer ".Length..];
        }
        var parts = token.Split('.');
        if (parts.Length != 3) return null;

        var payload = parts[1];
        // EN: Fix base64url padding / VI: Sửa padding base64url
        switch (payload.Length % 4)
        {
            case 2: payload += "=="; break;
            case 3: payload += "="; break;
        }
        payload = payload.Replace('-', '+').Replace('_', '/');

        try
        {
            var json = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(payload));
            using var doc = JsonDocument.Parse(json);
            if (doc.RootElement.TryGetProperty("sub", out var sub) && Guid.TryParse(sub.GetString(), out var userId))
                return userId;
        }
        catch { /* invalid token format */ }

        return null;
    }

    /// <summary>
    /// EN: Get wallet for the current user (extracted from JWT sub claim).
    /// VI: Lấy ví của user hiện tại (trích từ JWT sub claim).
    /// </summary>
    [HttpGet("wallets")]
    public async Task<IActionResult> GetWallets()
    {
        var userId = GetUserIdFromToken();
        if (userId == null)
            return Unauthorized(new { message = "Cannot extract user ID from token" });

        // EN: WalletService returns single wallet; wrap in array for frontend compatibility.
        // VI: WalletService trả về 1 ví; bọc trong array cho tương thích frontend.
        var response = await _wallet.GetAsync($"/api/v1/wallets/{userId}");
        var content = await response.Content.ReadAsStringAsync();

        if (!response.IsSuccessStatusCode)
        {
            // EN: If 404 or auth failure (401/403), return empty array (user has no wallet yet,
            //     or WalletService token validation failed in local dev).
            // VI: Nếu 404 hoặc lỗi auth (401/403), trả array rỗng (user chưa có ví,
            //     hoặc WalletService không validate được token khi chạy local dev).
            if (response.StatusCode is System.Net.HttpStatusCode.NotFound
                or System.Net.HttpStatusCode.Unauthorized
                or System.Net.HttpStatusCode.Forbidden)
                return new ContentResult { StatusCode = 200, Content = "[]", ContentType = "application/json" };

            return new ContentResult
            {
                StatusCode = (int)response.StatusCode,
                Content = content,
                ContentType = "application/json"
            };
        }

        // EN: Extract wallet data from ApiResponse envelope and wrap in array.
        // VI: Trích dữ liệu ví từ ApiResponse envelope và bọc trong array.
        try
        {
            using var doc = JsonDocument.Parse(content);
            if (doc.RootElement.TryGetProperty("data", out var data) && data.ValueKind == JsonValueKind.Object)
                return new ContentResult { StatusCode = 200, Content = $"[{data.GetRawText()}]", ContentType = "application/json" };
        }
        catch { /* fallback */ }

        return new ContentResult { StatusCode = 200, Content = $"[{content}]", ContentType = "application/json" };
    }

    /// <summary>
    /// EN: Get wallet transactions for the current user.
    /// VI: Lấy giao dịch ví của user hiện tại.
    /// </summary>
    [HttpGet("wallet/transactions")]
    public async Task<IActionResult> GetWalletTransactions([FromQuery] int limit = 50)
    {
        var userId = GetUserIdFromToken();
        if (userId == null)
            return Unauthorized(new { message = "Cannot extract user ID from token" });

        var response = await _wallet.GetAsync($"/api/v1/wallets/{userId}/transactions?limit={limit}");

        // EN: If wallet not found, return empty array (user has no wallet yet).
        // VI: Nếu ví không tồn tại, trả array rỗng (user chưa có ví).
        if (!response.IsSuccessStatusCode)
            return new ContentResult { StatusCode = 200, Content = "[]", ContentType = "application/json" };

        var content = await response.Content.ReadAsStringAsync();
        return new ContentResult { StatusCode = 200, Content = content, ContentType = "application/json" };
    }

    /// <summary>
    /// EN: Get promotions for current merchant.
    /// VI: Lấy danh sách khuyến mãi của merchant hiện tại.
    /// </summary>
    [HttpGet("promotions")]
    public Task<IActionResult> GetPromotions() =>
        _promotion.GetAsync("/api/v1/campaigns").ProxyAsync();

    /// <summary>
    /// EN: Get campaigns for current merchant.
    /// VI: Lấy danh sách chiến dịch của merchant hiện tại.
    /// </summary>
    [HttpGet("campaigns")]
    public Task<IActionResult> GetCampaigns([FromQuery] int pageSize = 100) =>
        _promotion.GetAsync($"/api/v1/admin/campaigns?pageSize={pageSize}").ProxyAsync();

    /// <summary>
    /// EN: Create a campaign. Enriches with default backing asset and acquisition fields.
    /// VI: Tạo chiến dịch. Bổ sung thông tin backing asset và acquisition mặc định.
    /// </summary>
    [HttpPost("campaigns")]
    public async Task<IActionResult> CreateCampaign([FromBody] JsonElement body)
    {
        // EN: Enrich with required fields using raw JSON manipulation
        // VI: Bổ sung các trường bắt buộc bằng thao tác JSON trực tiếp
        var rawJson = body.GetRawText();
        var defaults = new Dictionary<string, string>
        {
            ["backingAssetType"] = "\"currency\"",
            ["backingAssetCode"] = "\"VND\"",
            ["acquisitionType"] = "\"free\"",
            ["acquisitionPrice"] = "0",
            ["merchantId"] = $"\"{Guid.Empty}\"",
            ["merchantWalletId"] = $"\"{Guid.Empty}\""
        };
        foreach (var (key, val) in defaults)
        {
            if (!rawJson.Contains($"\"{key}\""))
                rawJson = rawJson.TrimEnd('}') + $",\"{key}\":{val}}}";
        }
        var content = new StringContent(rawJson, System.Text.Encoding.UTF8, "application/json");
        var resp = await _promotion.PostAsync("/api/v1/campaigns", content);
        var respContent = await resp.Content.ReadAsStringAsync();
        return new ContentResult
        {
            StatusCode = (int)resp.StatusCode,
            Content = respContent,
            ContentType = resp.Content.Headers.ContentType?.ToString() ?? "application/json"
        };
    }

    /// <summary>
    /// EN: Update a campaign.
    /// VI: Cập nhật chiến dịch.
    /// </summary>
    [HttpPut("campaigns/{campaignId:guid}")]
    public Task<IActionResult> UpdateCampaign(Guid campaignId, [FromBody] JsonElement body) =>
        _promotion.PutAsJsonAsync($"/api/v1/campaigns/{campaignId}", body).ProxyAsync();

    /// <summary>
    /// EN: Disable a campaign (soft-delete).
    /// VI: Vô hiệu hóa chiến dịch (xóa mềm).
    /// </summary>
    [HttpDelete("campaigns/{campaignId:guid}")]
    public Task<IActionResult> DeleteCampaign(Guid campaignId) =>
        _promotion.DeleteAsync($"/api/v1/campaigns/{campaignId}").ProxyAsync();

    // ═══ VOUCHER ENDPOINTS ═══

    /// <summary>
    /// EN: Validate a voucher code.
    /// VI: Kiểm tra mã voucher.
    /// </summary>
    [HttpGet("vouchers/validate/{code}")]
    public async Task<IActionResult> ValidateVoucher(string code)
    {
        var userId = GetUserIdFromToken();
        var qs = userId.HasValue ? $"?userId={userId}" : "";
        return await _promotion.GetAsync($"/api/v1/vouchers/validate/{code}{qs}").ProxyAsync();
    }

    /// <summary>
    /// EN: Redeem a voucher.
    /// VI: Sử dụng voucher.
    /// </summary>
    [HttpPost("vouchers/redeem")]
    public Task<IActionResult> RedeemVoucher([FromBody] JsonElement body) =>
        _promotion.PostAsJsonAsync("/api/v1/vouchers/redeem", body).ProxyAsync();

    // ═══ ADMIN VOUCHER MANAGEMENT ═══

    /// <summary>
    /// EN: List vouchers with optional filters (campaignId, status, codeSearch).
    /// VI: Liệt kê voucher với bộ lọc tùy chọn (campaignId, status, codeSearch).
    /// </summary>
    [HttpGet("vouchers/list")]
    public Task<IActionResult> GetAdminVouchers(
        [FromQuery] Guid? campaignId = null,
        [FromQuery] string? status = null,
        [FromQuery] string? codeSearch = null,
        [FromQuery] int pageSize = 50,
        [FromQuery] int page = 1)
    {
        var qs = new List<string> { $"pageSize={pageSize}", $"pageNumber={page}" };
        if (campaignId.HasValue) qs.Add($"campaignId={campaignId}");
        if (!string.IsNullOrEmpty(status)) qs.Add($"status={status}");
        if (!string.IsNullOrEmpty(codeSearch)) qs.Add($"codeSearch={Uri.EscapeDataString(codeSearch)}");
        return _promotion.GetAsync($"/api/v1/admin/vouchers?{string.Join("&", qs)}").ProxyAsync();
    }

    /// <summary>
    /// EN: Revoke a voucher.
    /// VI: Thu hồi voucher.
    /// </summary>
    [HttpPost("vouchers/{voucherId:guid}/revoke")]
    public Task<IActionResult> RevokeVoucher(Guid voucherId) =>
        _promotion.PostAsJsonAsync($"/api/v1/admin/vouchers/{voucherId}/revoke", new { reason = "Revoked by admin" }).ProxyAsync();

    /// <summary>
    /// EN: Activate a campaign.
    /// VI: Kích hoạt chiến dịch.
    /// </summary>
    [HttpPost("campaigns/{campaignId:guid}/activate")]
    public Task<IActionResult> ActivateCampaign(Guid campaignId) =>
        _promotion.PostAsync($"/api/v1/campaigns/{campaignId}/activate", null).ProxyAsync();

    /// <summary>
    /// EN: Pause a campaign.
    /// VI: Tạm dừng chiến dịch.
    /// </summary>
    [HttpPost("campaigns/{campaignId:guid}/pause")]
    public Task<IActionResult> PauseCampaign(Guid campaignId) =>
        _promotion.PostAsync($"/api/v1/campaigns/{campaignId}/pause", null).ProxyAsync();
}
