using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Электронная_Фармация.Properties;

namespace Электронная_Фармация.Classes
{
    /// <summary>
    /// Собирает доступные скидки покупателя/прайса/региона и вешает на позицию то, что пришло.
    /// Отсутствующий источник = 0.
    /// </summary>
    public static class DiscountResolver
    {
        public static async Task<DiscountLookup> LoadAsync(ApiClient client, string loginHint)
        {
            var lookup = new DiscountLookup();
            if (client == null)
            {
                return lookup;
            }

            var regionId = (Settings.Default.RegionId ?? string.Empty).Trim();
            lookup.RegionId = regionId;

            string buyerId = null;
            try
            {
                var buyers = await client.GetBuyersAsync();
                buyerId = ResolveBuyerId(buyers, loginHint);
                lookup.BuyerId = buyerId;
                AppDebugLog.Info(
                    "Discount",
                    string.IsNullOrWhiteSpace(buyerId)
                        ? "buyer_id не найден — клиентская скидка будет 0"
                        : $"buyer_id={buyerId}");
            }
            catch (Exception ex)
            {
                AppDebugLog.Warning("Discount", $"Не удалось загрузить покупателей: {ex.Message}");
            }

            List<BuyerPriceListAssignmentDto> assignments = null;
            if (!string.IsNullOrWhiteSpace(buyerId))
            {
                try
                {
                    assignments = await client.GetBuyerPriceListsAsync(buyerId);
                    AppDebugLog.Info("Discount", $"Назначений прайсов покупателя: {assignments?.Count ?? 0}");
                }
                catch (Exception ex)
                {
                    AppDebugLog.Warning("Discount", $"Не удалось загрузить buyer price-lists: {ex.Message}");
                }
            }

            List<PriceListDto> priceLists = null;
            try
            {
                priceLists = await client.GetPriceListsAsync();
                AppDebugLog.Info("Discount", $"Прайс-листов: {priceLists?.Count ?? 0}");
            }
            catch (Exception ex)
            {
                AppDebugLog.Warning("Discount", $"Не удалось загрузить price-lists: {ex.Message}");
            }

            EnrichAssignmentsFromPriceLists(assignments, priceLists);

            if (assignments != null)
            {
                foreach (var a in assignments)
                {
                    if (string.IsNullOrWhiteSpace(a?.PriceListId))
                    {
                        continue;
                    }

                    var plId = a.PriceListId.Trim();
                    lookup.ByPriceListId[plId] = new ItemDiscountParts
                    {
                        PriceListId = plId,
                        ClientDiscountPct = PositiveOrZero(a.MarkupPct),
                        PriceListDiscountPct = PositiveOrZero(a.DefaultMarkupPct),
                        RegionDiscountPct = 0m
                    };

                    IndexSupplierKeys(lookup, a.SupplierId, a.SupplierName, plId);
                }
            }

            if (priceLists != null)
            {
                foreach (var pl in priceLists)
                {
                    var plId = pl?.ResolvedId;
                    if (string.IsNullOrWhiteSpace(plId))
                    {
                        continue;
                    }

                    if (!lookup.ByPriceListId.TryGetValue(plId, out var parts))
                    {
                        parts = new ItemDiscountParts { PriceListId = plId };
                        lookup.ByPriceListId[plId] = parts;
                    }

                    if (parts.PriceListDiscountPct <= 0m && pl.DefaultMarkupPct.HasValue && pl.DefaultMarkupPct.Value > 0m)
                    {
                        parts.PriceListDiscountPct = pl.DefaultMarkupPct.Value;
                    }

                    IndexSupplierKeys(lookup, pl.SupplierId, pl.SupplierName, plId);
                }
            }

            foreach (var plId in lookup.ByPriceListId.Keys.ToList())
            {
                try
                {
                    var regions = await client.GetPriceListRegionsAsync(plId);
                    var regionPct = ResolveRegionDiscount(regions, regionId);
                    lookup.ByPriceListId[plId].RegionDiscountPct = regionPct;
                }
                catch (Exception ex)
                {
                    AppDebugLog.Warning("Discount", $"Регионы для прайса {plId}: {ex.Message}");
                }
            }

            AppDebugLog.Info(
                "Discount",
                $"Готово: прайсов={lookup.ByPriceListId.Count}, привязок по поставщику={lookup.BySupplierKey.Count}, region={regionId}");
            return lookup;
        }

        public static ItemDiscountParts ResolveForItem(DiscountLookup lookup, PriceSummaryItem item)
        {
            if (lookup == null || item == null)
            {
                return new ItemDiscountParts();
            }

            var priceListId = (item.PriceListId ?? string.Empty).Trim();
            if (!string.IsNullOrWhiteSpace(priceListId) &&
                lookup.ByPriceListId.TryGetValue(priceListId, out var byId))
            {
                return Clone(byId);
            }

            var supplierId = (item.SupplierId ?? string.Empty).Trim();
            if (!string.IsNullOrWhiteSpace(supplierId) &&
                lookup.BySupplierKey.TryGetValue(NormalizeKey(supplierId), out var plFromSupplier) &&
                lookup.ByPriceListId.TryGetValue(plFromSupplier, out var bySupplier))
            {
                return Clone(bySupplier);
            }

            var supplierName = (item.SupplierName ?? string.Empty).Trim();
            if (!string.IsNullOrWhiteSpace(supplierName) &&
                lookup.BySupplierKey.TryGetValue(NormalizeKey(supplierName), out var plFromName) &&
                lookup.ByPriceListId.TryGetValue(plFromName, out var byName))
            {
                return Clone(byName);
            }

            return new ItemDiscountParts();
        }

        private static string ResolveBuyerId(List<BuyerDto> buyers, string loginHint)
        {
            if (buyers == null || buyers.Count == 0)
            {
                return null;
            }

            var login = (loginHint ?? string.Empty).Trim();
            if (!string.IsNullOrWhiteSpace(login))
            {
                var matched = buyers.FirstOrDefault(b =>
                    string.Equals((b.Username ?? string.Empty).Trim(), login, StringComparison.OrdinalIgnoreCase) ||
                    string.Equals((b.Login ?? string.Empty).Trim(), login, StringComparison.OrdinalIgnoreCase) ||
                    string.Equals((b.Name ?? string.Empty).Trim(), login, StringComparison.OrdinalIgnoreCase));
                if (!string.IsNullOrWhiteSpace(matched?.ResolvedId))
                {
                    return matched.ResolvedId;
                }
            }

            if (buyers.Count == 1 && !string.IsNullOrWhiteSpace(buyers[0].ResolvedId))
            {
                return buyers[0].ResolvedId;
            }

            return buyers
                .Select(b => b.ResolvedId)
                .FirstOrDefault(id => !string.IsNullOrWhiteSpace(id));
        }

        private static void EnrichAssignmentsFromPriceLists(
            List<BuyerPriceListAssignmentDto> assignments,
            List<PriceListDto> priceLists)
        {
            if (assignments == null || priceLists == null || priceLists.Count == 0)
            {
                return;
            }

            var byId = priceLists
                .Where(p => !string.IsNullOrWhiteSpace(p?.ResolvedId))
                .GroupBy(p => p.ResolvedId, StringComparer.OrdinalIgnoreCase)
                .ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);

            foreach (var a in assignments)
            {
                if (a == null || string.IsNullOrWhiteSpace(a.PriceListId))
                {
                    continue;
                }

                if (!byId.TryGetValue(a.PriceListId.Trim(), out var pl))
                {
                    continue;
                }

                if (string.IsNullOrWhiteSpace(a.SupplierId))
                {
                    a.SupplierId = pl.SupplierId;
                }

                if (string.IsNullOrWhiteSpace(a.SupplierName))
                {
                    a.SupplierName = pl.SupplierName;
                }

                if ((!a.DefaultMarkupPct.HasValue || a.DefaultMarkupPct.Value <= 0m) &&
                    pl.DefaultMarkupPct.HasValue)
                {
                    a.DefaultMarkupPct = pl.DefaultMarkupPct;
                }
            }
        }

        private static decimal ResolveRegionDiscount(List<PriceListRegionDto> regions, string regionId)
        {
            if (regions == null || regions.Count == 0)
            {
                return 0m;
            }

            PriceListRegionDto match = null;
            if (!string.IsNullOrWhiteSpace(regionId))
            {
                match = regions.FirstOrDefault(r =>
                    string.Equals((r.RegionId ?? string.Empty).Trim(), regionId, StringComparison.OrdinalIgnoreCase) &&
                    (r.InWork == null || r.InWork.Value));
            }

            if (match == null)
            {
                match = regions.FirstOrDefault(r => r.InWork == true) ?? regions.FirstOrDefault();
            }

            return PositiveOrZero(match?.MarkupPct);
        }

        private static void IndexSupplierKeys(DiscountLookup lookup, string supplierId, string supplierName, string priceListId)
        {
            if (lookup == null || string.IsNullOrWhiteSpace(priceListId))
            {
                return;
            }

            if (!string.IsNullOrWhiteSpace(supplierId))
            {
                lookup.BySupplierKey[NormalizeKey(supplierId)] = priceListId;
            }

            if (!string.IsNullOrWhiteSpace(supplierName))
            {
                lookup.BySupplierKey[NormalizeKey(supplierName)] = priceListId;
            }
        }

        private static ItemDiscountParts Clone(ItemDiscountParts source)
        {
            if (source == null)
            {
                return new ItemDiscountParts();
            }

            return new ItemDiscountParts
            {
                PriceListId = source.PriceListId,
                PriceListDiscountPct = source.PriceListDiscountPct,
                RegionDiscountPct = source.RegionDiscountPct,
                ClientDiscountPct = source.ClientDiscountPct
            };
        }

        private static decimal PositiveOrZero(decimal? value)
        {
            return value.HasValue && value.Value > 0m ? value.Value : 0m;
        }

        private static string NormalizeKey(string value)
        {
            return (value ?? string.Empty).Trim().ToLowerInvariant();
        }
    }

    public sealed class DiscountLookup
    {
        public string BuyerId { get; set; }
        public string RegionId { get; set; }
        public Dictionary<string, ItemDiscountParts> ByPriceListId { get; } =
            new Dictionary<string, ItemDiscountParts>(StringComparer.OrdinalIgnoreCase);
        public Dictionary<string, string> BySupplierKey { get; } =
            new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
    }
}
