using System;
using System.Data.SQLite;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Электронная_Фармация.Properties;

namespace Электронная_Фармация.Classes
{
    /// <summary>
    /// Глобальные номера заказов вида EX-0000001.
    /// Источник истины — сервер (никогда не повторяются между аптеками).
    /// Offline fallback — локальный счётчик EX- (потом сервер может заменить при отправке).
    /// </summary>
    public static class OrderNumberHelper
    {
        private static readonly Regex ExPattern = new Regex(@"^EX-(\d{1,7})$", RegexOptions.IgnoreCase | RegexOptions.Compiled);

        /// <summary>
        /// Выделяет номер для нового локального заказа.
        /// Сначала пробует сервер /api/buyer/global-sign/next, иначе локальный EX-#######.
        /// </summary>
        public static string AllocateForNewOrder()
        {
            try
            {
                var fromServer = AllocateFromServerAsync().GetAwaiter().GetResult();
                if (!string.IsNullOrWhiteSpace(fromServer))
                {
                    return fromServer;
                }
            }
            catch (Exception ex)
            {
                AppDebugLog.Info("OrderNumber", $"Сервер недоступен для GlobalSign: {ex.Message}");
            }

            return AllocateLocalFallback();
        }

        public static async Task<string> AllocateFromServerAsync()
        {
            var token = Settings.Default.stringToken;
            var baseUrl = AppConfig.ApiBaseUrl;
            if (string.IsNullOrWhiteSpace(token) || string.IsNullOrWhiteSpace(baseUrl))
            {
                return null;
            }

            using (var client = new HttpClient { Timeout = TimeSpan.FromSeconds(8) })
            {
                client.BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/");
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Trim());
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                using (var response = await client.PostAsync("api/buyer/global-sign/next", new StringContent(string.Empty)).ConfigureAwait(false))
                {
                    var body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    if (!response.IsSuccessStatusCode)
                    {
                        AppDebugLog.Info("OrderNumber", $"global-sign/next HTTP {(int)response.StatusCode}: {body}");
                        return null;
                    }

                    using (var doc = JsonDocument.Parse(body))
                    {
                        if (doc.RootElement.TryGetProperty("global_sign", out var el))
                        {
                            var sign = el.GetString();
                            if (IsValidEx(sign))
                            {
                                return Normalize(sign);
                            }
                        }
                    }
                }
            }

            return null;
        }

        public static string AllocateLocalFallback()
        {
            long max = 0;
            try
            {
                using (var con = new SQLiteConnection(AppConfig.SqliteConnectionString))
                {
                    con.Open();
                    using (var cmd = new SQLiteCommand(
                        "SELECT OrderNumber FROM Orders WHERE OrderNumber LIKE 'EX-%'", con))
                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var n = ParseExNumber(reader[0]?.ToString());
                            if (n > max)
                            {
                                max = n;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                AppDebugLog.Info("OrderNumber", $"Локальный max EX-: {ex.Message}");
            }

            return FormatEx(max + 1);
        }

        public static bool IsValidEx(string value)
        {
            return ParseExNumber(value) > 0;
        }

        public static string Normalize(string value)
        {
            var n = ParseExNumber(value);
            return n > 0 ? FormatEx(n) : value?.Trim();
        }

        public static string FormatEx(long n)
        {
            if (n < 1)
            {
                n = 1;
            }

            if (n > 9999999)
            {
                return "EX-" + n.ToString();
            }

            return "EX-" + n.ToString("D7");
        }

        public static long ParseExNumber(string value)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                return 0;
            }

            var m = ExPattern.Match(value.Trim());
            if (!m.Success)
            {
                return 0;
            }

            return long.TryParse(m.Groups[1].Value, out var n) ? n : 0;
        }
    }
}
