using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Elfisa.Core;

namespace Elfisa.Avalonia.ViewModels;

/// <summary>Строка предложения с редактируемым количеством «Заказ» (как колонка «Заказ» в WinForms).</summary>
public partial class OfferRow : ObservableObject
{
    public PriceItem Source { get; }
    public string? DrugName => Source.DrugName;
    public string? SupplierName => Source.SupplierName;
    public decimal Price => Source.Price;
    public decimal Quantity => Source.Quantity;

    [ObservableProperty] private decimal _orderQty = 1;

    public OfferRow(PriceItem src) => Source = src;
}

/// <summary>
/// Прайс-лист + сборка заказа. Каталог — как в старой программе:
/// база (название) → дозировка (МГ) → предложения поставщиков. Справа «Мой заказ».
/// «Сохранить заказ» кладёт черновик в «Заказы» (статус «Не отправлен»).
/// </summary>
public partial class PriceListViewModel : ViewModelBase
{
    private readonly ApiClient _api = new();
    private readonly CartService _cart = CartService.Instance;

    // Плоский список предложений + предвычисленные база/МГ (как «Базовое наименование»/«МГ» в WinForms).
    private readonly List<(PriceItem Item, string BaseName, string Mg)> _indexed = new();

    private const string EmptyMgDisplay = "(без МГ)";
    private static readonly Regex DosageRegex = new(
        @"(\d+(?:[.,]\d+)?\s*(?:мг|мкг|г|мл|МЕ|ме)\b)",
        RegexOptions.IgnoreCase | RegexOptions.Compiled);

    // Три панели дрилдауна
    public ObservableCollection<string> BaseNames { get; } = new();
    public ObservableCollection<string> MgOptions { get; } = new();
    public ObservableCollection<OfferRow> Offers { get; } = new();

    public ObservableCollection<CartItem> Cart => _cart.Items;
    public ObservableCollection<BuyerLocationDto> Locations { get; } = new();

    [ObservableProperty] private string _search = "";
    [ObservableProperty] private string? _selectedBaseName;
    [ObservableProperty] private string? _selectedMg;
    [ObservableProperty] private OfferRow? _selectedOffer;
    [ObservableProperty] private BuyerLocationDto? _selectedLocation;
    [ObservableProperty] private string _comment = "";
    [ObservableProperty] private bool _busy;
    [ObservableProperty] private string? _status;
    [ObservableProperty] private int _total;
    [ObservableProperty] private decimal _cartTotal;

    public PriceListViewModel()
    {
        _api.SetToken(Session.Current.Token);
        _cart.Changed += Recalc;
        Recalc();
        if (Session.Current.IsAuthenticated)
        {
            _ = SearchAsync();
            _ = LoadLocationsAsync();
        }
    }

    private void Recalc() => CartTotal = _cart.Total;

    private async Task LoadLocationsAsync()
    {
        try
        {
            var locs = await _api.GetBuyerLocationsAsync();
            Locations.Clear();
            foreach (var l in locs) Locations.Add(l);
            var savedId = SettingsStore.Current.DefaultLocationId;
            SelectedLocation = Locations.FirstOrDefault(l => l.BuyerLocationId == savedId)
                               ?? Locations.FirstOrDefault(l => l.IsDefault)
                               ?? Locations.FirstOrDefault();
        }
        catch { }
    }

    [RelayCommand]
    private async Task SearchAsync()
    {
        Status = null;
        try
        {
            Busy = true;
            var resp = await _api.GetPriceSummaryAsync(Search, limit: 300);
            RebuildIndex(resp.Summary ?? new());
            Total = resp.TotalDrugs;
        }
        catch (Exception ex) { Status = ex.Message; }
        finally { Busy = false; }
    }

    /// <summary>Пересобирает индекс база/МГ и список базовых наименований.</summary>
    private void RebuildIndex(List<PriceItem> items)
    {
        _indexed.Clear();
        foreach (var it in items)
        {
            var mg = ExtractDosage(it.DrugName);
            var baseName = BuildBaseName(it.DrugName, it.TradeName, mg);
            if (string.IsNullOrWhiteSpace(baseName)) continue;
            _indexed.Add((it, baseName, mg));
        }

        // Сброс выбора и панелей
        SelectedBaseName = null;
        MgOptions.Clear();
        Offers.Clear();
        SelectedOffer = null;

        var names = _indexed
            .Select(x => x.BaseName)
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .OrderBy(n => n, StringComparer.OrdinalIgnoreCase)
            .ToList();

        BaseNames.Clear();
        foreach (var n in names) BaseNames.Add(n);
    }

    // База выбрана → заполняем список дозировок.
    partial void OnSelectedBaseNameChanged(string? value)
    {
        MgOptions.Clear();
        Offers.Clear();
        SelectedOffer = null;
        SelectedMg = null;
        if (string.IsNullOrEmpty(value)) return;

        var mgs = _indexed
            .Where(x => string.Equals(x.BaseName, value, StringComparison.OrdinalIgnoreCase))
            .Select(x => string.IsNullOrEmpty(x.Mg) ? EmptyMgDisplay : x.Mg)
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .OrderBy(m => m, StringComparer.OrdinalIgnoreCase)
            .ToList();

        foreach (var m in mgs) MgOptions.Add(m);

        // Если дозировка одна — сразу её выбираем (меньше кликов).
        if (MgOptions.Count == 1) SelectedMg = MgOptions[0];
    }

    // Дозировка выбрана → показываем предложения (фильтр база + МГ).
    partial void OnSelectedMgChanged(string? value)
    {
        Offers.Clear();
        SelectedOffer = null;
        if (string.IsNullOrEmpty(SelectedBaseName) || string.IsNullOrEmpty(value)) return;

        var wantMg = string.Equals(value, EmptyMgDisplay, StringComparison.Ordinal) ? "" : value;

        var offers = _indexed
            .Where(x => string.Equals(x.BaseName, SelectedBaseName, StringComparison.OrdinalIgnoreCase)
                     && string.Equals(x.Mg, wantMg, StringComparison.OrdinalIgnoreCase))
            .OrderBy(x => x.Item.Price)
            .Select(x => new OfferRow(x.Item))
            .ToList();

        foreach (var o in offers) Offers.Add(o);
        SelectedOffer = Offers.FirstOrDefault();
    }

    private static string ExtractDosage(string? drugName)
    {
        if (string.IsNullOrWhiteSpace(drugName)) return string.Empty;
        var m = DosageRegex.Match(drugName);
        return m.Success ? m.Value.Trim() : string.Empty;
    }

    private static string BuildBaseName(string? drugName, string? tradeName, string dosage)
    {
        if (!string.IsNullOrWhiteSpace(tradeName)) return tradeName.Trim();

        var name = drugName ?? string.Empty;
        if (!string.IsNullOrWhiteSpace(dosage))
        {
            var idx = name.IndexOf(dosage, StringComparison.OrdinalIgnoreCase);
            if (idx >= 0) name = name.Remove(idx, dosage.Length);
        }

        name = Regex.Replace(name, @"\s{2,}", " ").Trim(' ', ',', '-', '.', ';');
        return string.IsNullOrWhiteSpace(name) ? (drugName ?? string.Empty).Trim() : name;
    }

    [RelayCommand]
    private void AddToOrder() => AddSelectedOffer();

    /// <summary>Добавляет выбранное предложение в заказ с его количеством (Enter в таблице / кнопка).</summary>
    public void AddSelectedOffer()
    {
        if (SelectedOffer is null) { Status = "Выберите предложение в списке."; return; }
        var q = SelectedOffer.OrderQty <= 0 ? 1 : SelectedOffer.OrderQty;
        _cart.Add(SelectedOffer.Source, q);
        SelectedOffer.OrderQty = 1;
        Status = null;
    }

    [RelayCommand]
    private void RemoveFromCart(CartItem? item) => _cart.Remove(item!);

    [RelayCommand]
    private async Task SaveDraftAsync()
    {
        if (_cart.Count == 0) { Status = "Заказ пуст — добавьте позиции."; return; }
        try
        {
            Busy = true;
            // Резервируем настоящий номер заказа EX-####### (как в WinForms)
            var sign = await _api.NextGlobalSignAsync();

            var draft = new DraftOrder
            {
                Number = string.IsNullOrWhiteSpace(sign) ? $"ЧРН-{DateTime.Now:HHmmss}" : sign!,
                LocationId = SelectedLocation?.BuyerLocationId,
                LocationAddress = SelectedLocation?.Address,
                Comment = string.IsNullOrWhiteSpace(Comment) ? null : Comment.Trim(),
                Items = _cart.Items.Select(c => new DraftItem
                {
                    SupplierPriceId = c.Source.SupplierPriceId ?? "",
                    Name = c.Name,
                    Supplier = c.Supplier,
                    Barcode = c.Source.Barcode,
                    Price = c.Price,
                    Qty = c.Qty
                }).ToList()
            };
            DraftStore.Add(draft);
            _cart.Clear();
            Comment = "";
            Status = $"Заказ сохранён: {draft.Number} → раздел «Заказы» (не отправлен).";
        }
        catch (Exception ex) { Status = "Ошибка сохранения: " + ex.Message; }
        finally { Busy = false; }
    }
}
