using System.Globalization;
using System.Net;
using System.Text;
using System.Text.Json;
using Lada.Framework.Data.Domains;
using Lada.Framework.Data.Domains.Finance;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.Infrastructures.Helpers;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Finance;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace Ladaer.BackEnd.Infrastructures.Services.Finances
{
    /// <summary>
    /// Service đồng bộ hóa đơn VAT từ API Tổng cục Thuế
    /// </summary>
    public class VatInvoiceSyncService : IVatInvoiceSyncService
    {
        private readonly IRepository<VatInvoice> _repository;
        private readonly IRepository<VatInvoiceSyncHistory> _syncHistoryRepository;
        private readonly IRepository<AppConfig> _appConfigRepository;
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly ILogger<VatInvoiceSyncService> _logger;

        public VatInvoiceSyncService(
            IRepository<VatInvoice> repository,
            IRepository<VatInvoiceSyncHistory> syncHistoryRepository,
            IRepository<AppConfig> appConfigRepository,
            IHttpClientFactory httpClientFactory,
            ILogger<VatInvoiceSyncService> logger)
        {
            _repository = repository;
            _syncHistoryRepository = syncHistoryRepository;
            _appConfigRepository = appConfigRepository;
            _httpClientFactory = httpClientFactory;
            _logger = logger;
        }

        /// <summary>
        /// Đồng bộ hóa đơn từ API Tổng cục Thuế (tự động chia nhỏ nếu khoảng ngày > 30 ngày)
        /// </summary>
        public async Task<BaseResult> SyncInvoicesFromAPI(DateTimeOffset fromDate, DateTimeOffset toDate, string syncType = "Manual", int? userId = null, int invoiceDirection = 1)
        {
            var totalDays = (toDate - fromDate).TotalDays;

            // Nếu <= 30 ngày, gọi trực tiếp
            if (totalDays <= 30)
            {
                return await SyncInvoicesBatch(fromDate, toDate, syncType, userId, invoiceDirection);
            }

            // Chia nhỏ thành các batch 30 ngày
            _logger.LogInformation("Khoảng ngày ({TotalDays} ngày) vượt quá 30 ngày, chia thành các batch 30 ngày.", (int)totalDays);

            int totalInserted = 0;
            int totalUpdated = 0;
            int batchCount = 0;
            var currentFrom = fromDate;

            while (currentFrom < toDate)
            {
                var currentTo = currentFrom.AddDays(30);
                if (currentTo > toDate) currentTo = toDate;

                batchCount++;
                _logger.LogInformation("Đồng bộ batch {BatchCount}: {From:dd/MM/yyyy} → {To:dd/MM/yyyy}", batchCount, currentFrom, currentTo);

                var batchResult = await SyncInvoicesBatch(currentFrom, currentTo, syncType, userId, invoiceDirection);

                if (batchResult.Result != Result.Success)
                {
                    return new BaseResult
                    {
                        Result = Result.Failed,
                        Message = $"Lỗi tại batch {batchCount} ({currentFrom:dd/MM/yyyy} - {currentTo:dd/MM/yyyy}): {batchResult.Message}. " +
                                  $"Trước đó đã đồng bộ {totalInserted} mới, {totalUpdated} cập nhật."
                    };
                }

                // Trích xuất số lượng từ sync history (batch cuối cùng ghi vào DB)
                var lastSync = await _syncHistoryRepository.Query()
                    .OrderByDescending(x => x.SyncStartTime)
                    .FirstOrDefaultAsync();
                if (lastSync != null)
                {
                    totalInserted += lastSync.InsertedCount;
                    totalUpdated += lastSync.UpdatedCount;
                }

                currentFrom = currentTo.AddDays(1);

                // Delay giữa các batch để tránh quá tải API
                if (currentFrom < toDate)
                {
                    await Task.Delay(TimeSpan.FromMilliseconds(500));
                }
            }

            return new BaseResult
            {
                Result = Result.Success,
                Message = $"Đồng bộ thành công {totalInserted} hóa đơn mới và cập nhật {totalUpdated} hóa đơn ({batchCount} batch)"
            };
        }

        /// <summary>
        /// Đồng bộ hóa đơn cho một batch đơn lẻ (tối đa 30 ngày)
        /// </summary>
        private async Task<BaseResult> SyncInvoicesBatch(DateTimeOffset fromDate, DateTimeOffset toDate, string syncType, int? userId, int invoiceDirection)
        {
            var startTime = DateTimeOffset.Now;
            var syncHistory = new VatInvoiceSyncHistory
            {
                SyncStartTime = startTime,
                FromDate = fromDate.ToLocalTime().StartOfDay(),
                ToDate = toDate.ToLocalTime().EndOfDay(),
                SyncType = syncType,
                InvoiceDirection = invoiceDirection,
                UserId = userId,
                Status = "InProgress",
                ErrorMessage = "",
                InsertedCount = 0,
                UpdatedCount = 0,
                CreatedTime = startTime,
                UpdatedTime = startTime
            };

            try
            {
                // Lấy cấu hình từ database
                var configs = await _appConfigRepository.Query()
                    .Where(x => x.Key.StartsWith("VatApi."))
                    .ToListAsync();

                var bearerToken = configs.FirstOrDefault(x => x.Key == "VatApi.BearerToken")?.Value;
                var baseUrl = configs.FirstOrDefault(x => x.Key == "VatApi.BaseUrl")?.Value ?? "https://hoadondientu.gdt.gov.vn:30000";
                var sortParam = configs.FirstOrDefault(x => x.Key == "VatApi.SortParam")?.Value ?? "tdlap:desc";
                var pageSize = int.Parse(configs.FirstOrDefault(x => x.Key == "VatApi.PageSize")?.Value ?? "50");
                var searchFormat = configs.FirstOrDefault(x => x.Key == "VatApi.SearchFormat")?.Value ?? "tdlap=ge={fromDate};tdlap=le={toDate}";

                // Nếu chưa có token, tự động lấy token mới
                if (string.IsNullOrEmpty(bearerToken))
                {
                    _logger.LogWarning("Bearer token rỗng, đang tự động refresh token...");
                    bearerToken = await RefreshBearerToken(baseUrl, configs);
                    if (string.IsNullOrEmpty(bearerToken))
                    {
                        var errorMsg = "Không thể lấy Bearer Token tự động. Vui lòng kiểm tra cấu hình VatApi.Username và VatApi.Password trong AppConfig.";
                        syncHistory.Status = "Failed";
                        syncHistory.ErrorMessage = errorMsg;
                        syncHistory.SyncEndTime = DateTimeOffset.Now;
                        syncHistory.DurationSeconds = (DateTimeOffset.Now - startTime).TotalSeconds;
                        await _syncHistoryRepository.InsertAsync(syncHistory);

                        return new BaseResult
                        {
                            Result = Result.Failed,
                            Message = errorMsg
                        };
                    }
                }

                // Format ngày theo chuẩn của API GDT (dd/MM/yyyyTHH:mm:ss)
                var fromDateStr = fromDate.ToLocalTime().StartOfDay().ToString("dd/MM/yyyy") + "T00:00:00";
                var toDateStr = toDate.ToLocalTime().EndOfDay().ToString("dd/MM/yyyy") + "T23:59:59";

                // Build search query
                var searchQuery = searchFormat
                    .Replace("{fromDate}", fromDateStr)
                    .Replace("{toDate}", toDateStr);

                // Gọi API với khả năng retry khi token hết hạn
                var syncTime = DateTimeOffset.Now;
                int insertedCount = 0;
                int updatedCount = 0;
                bool tokenRefreshed = false;

            RetrySync:
                using (var httpClient = _httpClientFactory.CreateClient())
                {
                    httpClient.DefaultRequestHeaders.Clear();
                    httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {bearerToken}");
                    httpClient.DefaultRequestHeaders.Add("Accept", "application/json");

                    try
                    {
                        if (invoiceDirection == 2)
                        {
                            // Hóa đơn mua vào: gọi 3 lần cho 3 loại kết quả kiểm tra
                            int[] ttxlyValues = { 5, 6, 8 };
                            for (int i = 0; i < ttxlyValues.Length; i++)
                            {
                                // Delay 30s giữa các lần gọi ttxly để tránh TooManyRequests
                                if (i > 0) await Task.Delay(TimeSpan.FromMilliseconds(500));

                                var ttxly = ttxlyValues[i];
                                var purchaseSearchQuery = searchQuery + $";ttxly=={ttxly}";
                                var (inserted, updated) = await FetchAndProcessInvoices(
                                    httpClient, baseUrl, sortParam, pageSize,
                                    purchaseSearchQuery, "purchase", invoiceDirection, syncTime, ttxly);
                                insertedCount += inserted;
                                updatedCount += updated;
                            }

                            // Hóa đơn từ máy tính tiền (SCO) - chỉ mua vào, ttxly=8
                            await Task.Delay(TimeSpan.FromMilliseconds(500));
                            var scoSearchQuery = searchQuery + ";ttxly==8";
                            var (scoInserted, scoUpdated) = await FetchAndProcessInvoices(
                                httpClient, baseUrl, sortParam, pageSize,
                                scoSearchQuery, "purchase", invoiceDirection, syncTime, 8,
                                useScoQuery: true);
                            insertedCount += scoInserted;
                            updatedCount += scoUpdated;
                        }
                        else
                        {
                            // Hóa đơn bán ra: gọi 1 lần
                            var (inserted, updated) = await FetchAndProcessInvoices(
                                httpClient, baseUrl, sortParam, pageSize,
                                searchQuery, "sold", invoiceDirection, syncTime, 0);
                            insertedCount += inserted;
                            updatedCount += updated;
                        }
                    }
                    catch (TokenExpiredException) when (!tokenRefreshed)
                    {
                        // Token hết hạn, refresh và retry
                        _logger.LogWarning("Token hết hạn (401), đang tự động refresh token...");
                        var newConfigs = await _appConfigRepository.Query()
                            .Where(x => x.Key.StartsWith("VatApi."))
                            .ToListAsync();
                        bearerToken = await RefreshBearerToken(baseUrl, newConfigs);
                        if (!string.IsNullOrEmpty(bearerToken))
                        {
                            tokenRefreshed = true;
                            insertedCount = 0;
                            updatedCount = 0;
                            goto RetrySync;
                        }
                        throw new Exception("Không thể refresh token sau khi nhận 401 Unauthorized.");
                    }
                }

                if (insertedCount == 0 && updatedCount == 0)
                {
                    var msg = $"Không có hóa đơn nào trong khoảng {fromDateStr} đến {toDateStr}";
                    syncHistory.Status = "Success";
                    syncHistory.SyncEndTime = DateTimeOffset.Now;
                    syncHistory.DurationSeconds = (DateTimeOffset.Now - startTime).TotalSeconds;
                    await _syncHistoryRepository.InsertAsync(syncHistory);

                    return new BaseResult
                    {
                        Result = Result.Success,
                        Message = msg
                    };
                }

                // Lưu sync history với kết quả thành công
                syncHistory.Status = "Success";
                syncHistory.InsertedCount = insertedCount;
                syncHistory.UpdatedCount = updatedCount;
                syncHistory.SyncEndTime = DateTimeOffset.Now;
                syncHistory.DurationSeconds = (DateTimeOffset.Now - startTime).TotalSeconds;
                await _syncHistoryRepository.InsertAsync(syncHistory);

                return new BaseResult
                {
                    Result = Result.Success,
                    Message = $"Đồng bộ thành công {insertedCount} hóa đơn mới và cập nhật {updatedCount} hóa đơn"
                };
            }
            catch (Exception ex)
            {
                // Lưu sync history với lỗi
                syncHistory.Status = "Failed";
                syncHistory.ErrorMessage = ex.Message;
                syncHistory.SyncEndTime = DateTimeOffset.Now;
                syncHistory.DurationSeconds = (DateTimeOffset.Now - startTime).TotalSeconds;
                try { await _syncHistoryRepository.InsertAsync(syncHistory); } catch { /* ignore if saving history also fails */ }

                return new BaseResult
                {
                    Result = Result.Failed,
                    Message = $"Lỗi khi đồng bộ hóa đơn: {ex.Message}"
                };
            }
        }

        /// <summary>
        /// Đồng bộ hóa đơn của ngày hôm qua
        /// </summary>
        public async Task<BaseResult> SyncYesterdayInvoices()
        {
            var yesterday = DateTimeOffset.Now.AddDays(-1);
            var startOfYesterday = new DateTimeOffset(yesterday.Date, yesterday.Offset);
            var endOfYesterday = startOfYesterday.AddDays(1).AddTicks(-1);

            return await SyncInvoicesFromAPI(startOfYesterday, endOfYesterday, syncType: "Auto", userId: null, invoiceDirection: 1);
        }

        /// <summary>
        /// Đồng bộ hóa đơn mua vào của ngày hôm qua
        /// </summary>
        public async Task<BaseResult> SyncYesterdayPurchaseInvoices()
        {
            var yesterday = DateTimeOffset.Now.AddDays(-1);
            var startOfYesterday = new DateTimeOffset(yesterday.Date, yesterday.Offset);
            var endOfYesterday = startOfYesterday.AddDays(1).AddTicks(-1);

            return await SyncInvoicesFromAPI(startOfYesterday, endOfYesterday, syncType: "Auto", userId: null, invoiceDirection: 2);
        }

        /// <summary>
        /// Lấy thông tin đồng bộ gần nhất
        /// </summary>
        public async Task<VatInvoiceSyncInfo> GetLastSyncInfo()
        {
            var lastSync = await _syncHistoryRepository.Query()
                .OrderByDescending(x => x.SyncStartTime)
                .FirstOrDefaultAsync();

            if (lastSync == null)
            {
                return new VatInvoiceSyncInfo
                {
                    HasSyncHistory = false,
                    Message = "Chưa có lịch sử đồng bộ nào"
                };
            }

            var dateRange = $"{lastSync.FromDate:dd/MM/yyyy} - {lastSync.ToDate:dd/MM/yyyy}";

            return new VatInvoiceSyncInfo
            {
                HasSyncHistory = true,
                LastSyncTime = lastSync.SyncStartTime,
                SyncDateRange = dateRange,
                Status = lastSync.Status,
                InsertedCount = lastSync.InsertedCount,
                UpdatedCount = lastSync.UpdatedCount,
                TotalCount = lastSync.InsertedCount + lastSync.UpdatedCount,
                DurationSeconds = lastSync.DurationSeconds,
                SyncType = lastSync.SyncType,
                ErrorMessage = lastSync.ErrorMessage,
                Message = lastSync.Status == "Success"
                    ? $"Lần đồng bộ gần nhất: {lastSync.SyncStartTime:dd/MM/yyyy HH:mm:ss} ({lastSync.SyncType})"
                    : $"Lần đồng bộ gần nhất thất bại: {lastSync.SyncStartTime:dd/MM/yyyy HH:mm:ss}"
            };
        }

        #region Token Refresh

        /// <summary>
        /// Tự động lấy Bearer Token mới từ API GDT bằng cách giải captcha và đăng nhập
        /// </summary>
        private async Task<string?> RefreshBearerToken(string baseUrl, List<AppConfig> configs)
        {
            var username = configs.FirstOrDefault(x => x.Key == "VatApi.Username")?.Value;
            var password = configs.FirstOrDefault(x => x.Key == "VatApi.Password")?.Value;

            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            {
                _logger.LogError("Chưa cấu hình VatApi.Username hoặc VatApi.Password trong AppConfig.");
                return null;
            }

            const int maxRetries = 3;
            for (int attempt = 1; attempt <= maxRetries; attempt++)
            {
                try
                {
                    _logger.LogInformation("Refresh token lần {Attempt}/{MaxRetries}...", attempt, maxRetries);

                    using var httpClient = _httpClientFactory.CreateClient();
                    SetCommonHeaders(httpClient);

                    // Bước 1: Lấy captcha
                    var captchaResponse = await httpClient.GetAsync($"{baseUrl}/captcha");
                    captchaResponse.EnsureSuccessStatusCode();

                    var captchaJson = await captchaResponse.Content.ReadAsStringAsync();
                    var captchaData = JsonSerializer.Deserialize<CaptchaResponse>(captchaJson, new JsonSerializerOptions
                    {
                        PropertyNameCaseInsensitive = true
                    });

                    if (captchaData == null || string.IsNullOrEmpty(captchaData.Key) || string.IsNullOrEmpty(captchaData.Content))
                    {
                        _logger.LogWarning("Captcha response không hợp lệ (lần {Attempt}).", attempt);
                        continue;
                    }

                    // Bước 2: Giải captcha
                    var solver = new SvgCaptchaSolver();
                    var captchaValue = solver.SolveCaptchaFromContent(captchaData.Content);
                    _logger.LogInformation("Captcha đã giải: {CaptchaValue} (key: {CaptchaKey})", captchaValue, captchaData.Key);

                    // Bước 3: Đăng nhập
                    var authRequest = new AuthenticateRequest
                    {
                        Username = username,
                        Password = password,
                        Cvalue = captchaValue,
                        Ckey = captchaData.Key
                    };

                    var authContent = new StringContent(
                        JsonSerializer.Serialize(authRequest, new JsonSerializerOptions
                        {
                            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                        }),
                        Encoding.UTF8,
                        "application/json");

                    var authResponse = await httpClient.PostAsync($"{baseUrl}/security-taxpayer/authenticate", authContent);
                    var authJson = await authResponse.Content.ReadAsStringAsync();

                    if (!authResponse.IsSuccessStatusCode)
                    {
                        _logger.LogWarning("Đăng nhập thất bại (lần {Attempt}): {StatusCode} - {Body}", attempt, authResponse.StatusCode, authJson);
                        if (attempt < maxRetries)
                        {
                            await Task.Delay(TimeSpan.FromSeconds(2));
                        }
                        continue;
                    }

                    var authResult = JsonSerializer.Deserialize<AuthenticateResponse>(authJson, new JsonSerializerOptions
                    {
                        PropertyNameCaseInsensitive = true
                    });

                    if (authResult == null || string.IsNullOrEmpty(authResult.Token))
                    {
                        _logger.LogWarning("Response đăng nhập không chứa token (lần {Attempt}).", attempt);
                        continue;
                    }

                    // Bước 4: Lưu token vào AppConfig
                    var tokenConfig = await _appConfigRepository.Query()
                        .FirstOrDefaultAsync(x => x.Key == "VatApi.BearerToken");

                    if (tokenConfig != null)
                    {
                        tokenConfig.Value = authResult.Token;
                        tokenConfig.UpdatedTime = DateTimeOffset.Now;
                        await _appConfigRepository.UpdateAsync(tokenConfig);
                    }
                    else
                    {
                        var newConfig = new AppConfig
                        {
                            Key = "VatApi.BearerToken",
                            Value = authResult.Token,
                            Description = "Bearer Token cho VAT API (tự động cập nhật)",
                            CreatedTime = DateTimeOffset.Now,
                            UpdatedTime = DateTimeOffset.Now
                        };
                        await _appConfigRepository.InsertAsync(newConfig);
                    }

                    _logger.LogInformation("Refresh token thành công.");
                    return authResult.Token;
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, "Lỗi khi refresh token (lần {Attempt}/{MaxRetries}).", attempt, maxRetries);
                    if (attempt < maxRetries)
                    {
                        await Task.Delay(TimeSpan.FromSeconds(2));
                    }
                }
            }

            _logger.LogError("Không thể refresh token sau {MaxRetries} lần thử.", maxRetries);
            return null;
        }

        /// <summary>
        /// Set các header phổ biến giống browser cho request tới GDT
        /// </summary>
        private static void SetCommonHeaders(HttpClient httpClient)
        {
            httpClient.DefaultRequestHeaders.Add("Accept", "application/json, text/plain, */*");
            httpClient.DefaultRequestHeaders.Add("Accept-Language", "vi-VN,vi;q=0.9,en-US;q=0.8,en;q=0.7");
            httpClient.DefaultRequestHeaders.Add("Origin", "https://hoadondientu.gdt.gov.vn");
            httpClient.DefaultRequestHeaders.Add("Referer", "https://hoadondientu.gdt.gov.vn/");
            httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36");
        }

        #endregion

        #region Private Helpers

        /// <summary>
        /// Gọi API GDT và xử lý kết quả (insert/update hóa đơn) - hỗ trợ phân trang cursor-based
        /// </summary>
        private async Task<(int inserted, int updated)> FetchAndProcessInvoices(
            HttpClient httpClient, string baseUrl, string sortParam, int pageSize,
            string searchQuery, string invoiceEndpoint, int invoiceDirection,
            DateTimeOffset syncTime, int invoiceCheckResult,
            bool useScoQuery = false)
        {
            int insertedCount = 0;
            int updatedCount = 0;
            string state = null;
            int totalFetched = 0;

            // Sử dụng sco-query cho hóa đơn từ máy tính tiền
            var queryPath = useScoQuery ? "sco-query" : "query";

            while (true)
            {
                // Build URL: trang 1 không có state, trang 2+ có state
                var requestUrl = state == null
                    ? $"{baseUrl}/{queryPath}/invoices/{invoiceEndpoint}?sort={sortParam}&size={pageSize}&search={searchQuery}"
                    : $"{baseUrl}/{queryPath}/invoices/{invoiceEndpoint}?sort={sortParam}&size={pageSize}&state={state}&search={searchQuery}";

                var response = await httpClient.GetAsync(requestUrl);

                // Phát hiện token hết hạn
                if (response.StatusCode == HttpStatusCode.Unauthorized)
                {
                    throw new TokenExpiredException("API trả về 401 Unauthorized - token hết hạn.");
                }

                if (!response.IsSuccessStatusCode)
                {
                    throw new Exception($"API call failed with status code: {response.StatusCode} (ttxly={invoiceCheckResult})");
                }

                var jsonContent = await response.Content.ReadAsStringAsync();
                var apiResponse = JsonSerializer.Deserialize<ApiResponse>(jsonContent, new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true
                });

                if (apiResponse?.Datas == null || !apiResponse.Datas.Any())
                {
                    break;
                }

                // Xử lý từng hóa đơn trong trang hiện tại
                var deserializeOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
                foreach (var invoiceElement in apiResponse.Datas)
                {
                    // Lưu JSON gốc từ API (chứa đầy đủ dữ liệu, không chỉ các trường đã map)
                    var rawJson = invoiceElement.GetRawText();
                    var invoiceData = JsonSerializer.Deserialize<InvoiceData>(rawJson, deserializeOptions);

                    var externalId = invoiceData.Id?.ToString();
                    if (string.IsNullOrEmpty(externalId)) continue;

                    // Lấy giá trị ttxly từ dữ liệu hóa đơn, fallback về giá trị mặc định
                    var actualCheckResult = invoiceData.Ttxly ?? invoiceCheckResult;

                    // Kiểm tra xem hóa đơn đã tồn tại chưa (theo ExternalId + InvoiceDirection)
                    var existing = await _repository.Query()
                        .FirstOrDefaultAsync(x => x.ExternalId == externalId && x.InvoiceDirection == invoiceDirection);

                    if (existing == null)
                    {
                        // Insert mới
                        var newInvoice = MapToEntity(invoiceData, rawJson, syncTime, invoiceDirection, actualCheckResult);
                        await _repository.InsertAsync(newInvoice);
                        insertedCount++;
                    }
                    else
                    {
                        // Update
                        UpdateEntity(existing, invoiceData, rawJson, syncTime, invoiceDirection, actualCheckResult);
                        await _repository.UpdateAsync(existing);
                        updatedCount++;
                    }
                }

                totalFetched += apiResponse.Datas.Count;
                state = apiResponse.State;

                // Điều kiện dừng: hết data, không có state tiếp, hoặc đã lấy đủ total
                if (string.IsNullOrEmpty(state)) break;
                if (totalFetched >= (apiResponse.Total ?? 0)) break;

                // Delay 5s trước khi gọi trang tiếp theo để tránh TooManyRequests
                await Task.Delay(TimeSpan.FromMilliseconds(500));
            }

            return (insertedCount, updatedCount);
        }

        /// <summary>
        /// Map dữ liệu từ API sang Entity
        /// </summary>
        private VatInvoice MapToEntity(InvoiceData data, string rawJson, DateTimeOffset syncTime, int invoiceDirection = 1, int invoiceCheckResult = 0)
        {
            return new VatInvoice
            {
                ExternalId = data.Id?.ToString() ?? "",
                TemplateCode = data.Khmshdon ?? 0,
                InvoiceSymbol = data.Khhdon ?? "",
                InvoiceNumber = data.Shdon?.ToString() ?? "",
                InvoiceType = data.Hdon ?? "",
                IssueDate = ParseDate(data.Tdlap),
                SellerTaxCode = data.Nbmst ?? "",
                SellerName = data.Nbten ?? "",
                SellerAddress = data.Nbdchi ?? "",
                BuyerTaxCode = data.Nmmst ?? "",
                BuyerName = data.Nmten ?? "",
                BuyerAddress = data.Nmdchi ?? "",
                CustomerCode = data.Mkhang ?? "",
                AmountBeforeTax = data.Tgtcthue ?? 0,
                TaxAmount = data.Tgtthue ?? 0,
                TotalAmount = data.Tgtttbso ?? 0,
                Currency = data.Dvtte ?? "VND",
                PaymentMethod = data.Htttoan ?? 0,
                PaymentMethodText = data.Thtttoan ?? "",
                Status = data.Tthai ?? 0,
                Note = data.Gchu ?? "",
                RawJsonData = rawJson,
                SyncTime = syncTime,
                InvoiceDirection = invoiceDirection,
                InvoiceCheckResult = invoiceCheckResult,
                CreatedTime = syncTime,
                UpdatedTime = syncTime
            };
        }

        /// <summary>
        /// Cập nhật entity từ API data
        /// </summary>
        private void UpdateEntity(VatInvoice entity, InvoiceData data, string rawJson, DateTimeOffset syncTime, int invoiceDirection = 1, int invoiceCheckResult = 0)
        {
            entity.TemplateCode = data.Khmshdon ?? 0;
            entity.InvoiceSymbol = data.Khhdon ?? "";
            entity.InvoiceNumber = data.Shdon?.ToString() ?? "";
            entity.InvoiceType = data.Hdon ?? "";
            entity.IssueDate = ParseDate(data.Tdlap);
            entity.SellerTaxCode = data.Nbmst ?? "";
            entity.SellerName = data.Nbten ?? "";
            entity.SellerAddress = data.Nbdchi ?? "";
            entity.BuyerTaxCode = data.Nmmst ?? "";
            entity.BuyerName = data.Nmten ?? "";
            entity.BuyerAddress = data.Nmdchi ?? "";
            entity.CustomerCode = data.Mkhang ?? "";
            entity.AmountBeforeTax = data.Tgtcthue ?? 0;
            entity.TaxAmount = data.Tgtthue ?? 0;
            entity.TotalAmount = data.Tgtttbso ?? 0;
            entity.Currency = data.Dvtte ?? "VND";
            entity.PaymentMethod = data.Htttoan ?? 0;
            entity.PaymentMethodText = data.Thtttoan ?? "";
            entity.Status = data.Tthai ?? 0;
            entity.Note = data.Gchu ?? "";
            entity.RawJsonData = rawJson;
            entity.SyncTime = syncTime;
            entity.InvoiceDirection = invoiceDirection;
            entity.InvoiceCheckResult = invoiceCheckResult;
            entity.UpdatedTime = syncTime;
        }

        /// <summary>
        /// Parse date từ API (có thể là string hoặc long timestamp)
        /// </summary>
        private static readonly TimeSpan VietnamOffset = TimeSpan.FromHours(7);
        private static readonly TimeZoneInfo VietnamTimeZone = TimeZoneInfo.CreateCustomTimeZone("VN", VietnamOffset, "Vietnam", "Vietnam");

        private DateTimeOffset ParseDate(string dateString)
        {
            if (string.IsNullOrEmpty(dateString))
                return DateTimeOffset.MinValue;

            // Thử parse ISO format (API GDT trả về UTC, cần chuyển sang GMT+7)
            if (DateTimeOffset.TryParse(dateString, out var result))
            {
                // Chuyển từ UTC sang giờ Việt Nam (GMT+7)
                return result.ToOffset(VietnamOffset);
            }

            // Thử parse dd/MM/yyyy
            if (DateTime.TryParseExact(dateString, "dd/MM/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt))
                return new DateTimeOffset(dt, VietnamOffset);

            return DateTimeOffset.MinValue;
        }

        #endregion

        #region Models

        /// <summary>
        /// Exception đánh dấu token hết hạn để trigger retry logic
        /// </summary>
        private class TokenExpiredException : Exception
        {
            public TokenExpiredException(string message) : base(message) { }
        }

        private class ApiResponse
        {
            public List<JsonElement> Datas { get; set; }
            public int? Total { get; set; }
            public string State { get; set; }
        }

        private class InvoiceData
        {
            public object Id { get; set; }
            public int? Khmshdon { get; set; }  // Ký hiệu mẫu số
            public string Khhdon { get; set; }  // Ký hiệu hóa đơn
            public int? Shdon { get; set; }      // Số hóa đơn
            public string Hdon { get; set; }    // Loại hóa đơn
            public string Tdlap { get; set; }   // Ngày lập
            public string Nmmst { get; set; }   // MST người mua
            public string Nmten { get; set; }   // Tên người mua
            public string Nmdchi { get; set; }  // Địa chỉ người mua
            public string Nbmst { get; set; }   // MST người bán
            public string Nbten { get; set; }   // Tên người bán
            public string Nbdchi { get; set; }  // Địa chỉ người bán
            public string Mkhang { get; set; }  // Mã khách hàng
            public decimal? Tgtcthue { get; set; } // Tổng tiền hàng
            public decimal? Tgtthue { get; set; }  // Tổng tiền thuế
            public decimal? Tgtttbso { get; set; } // Tổng thanh toán
            public string Dvtte { get; set; }   // Đơn vị tiền tệ
            public int? Htttoan { get; set; }   // Hình thức thanh toán
            public string Thtttoan { get; set; }// Tên hình thức thanh toán
            public int? Tthai { get; set; }     // Tình trạng
            public string Gchu { get; set; }    // Ghi chú
            public int? Ttxly { get; set; }     // Kết quả xử lý
        }

        private class CaptchaResponse
        {
            public string Key { get; set; }
            public string Content { get; set; }
        }

        private class AuthenticateRequest
        {
            public string Username { get; set; }
            public string Password { get; set; }
            public string Cvalue { get; set; }
            public string Ckey { get; set; }
        }

        private class AuthenticateResponse
        {
            public string Token { get; set; }
        }

        #endregion
    }
}
