using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Elfisa.Core;

namespace Elfisa.Avalonia.ViewModels;

public sealed class ReportColumn
{
    public string Header { get; init; } = "";
    public bool Numeric { get; init; }
    public double Weight { get; init; } = 100;   // ширина в пикселях (для нетянущихся)
    public bool Stretch { get; init; }            // тянуть на всё свободное место (star)
}

/// <summary>Строка отчёта: ячейки как строки, доступ по индексу для DataGrid.</summary>
public sealed class ReportRow
{
    private readonly string[] _cells;
    public ReportRow(string[] cells) => _cells = cells;
    public string this[int i] => i >= 0 && i < _cells.Length ? _cells[i] : "";
}

public partial class ReportsViewModel : ViewModelBase
{
    private readonly ApiClient _api = new();
    private List<BuyerReportLineDto> _lines = new();

    /// <summary>Сигнал View пересобрать колонки DataGrid.</summary>
    public event Action? ColumnsChanged;

    public ObservableCollection<ReportColumn> Columns { get; } = new();
    public ObservableCollection<ReportRow> Rows { get; } = new();

    [ObservableProperty] private DateTimeOffset _dateFrom = DateTimeOffset.Now.AddMonths(-1);
    [ObservableProperty] private DateTimeOffset _dateTo = DateTimeOffset.Now;

    public string[] ReportTypes { get; } = { "Мои заказы", "По поставщикам", "По товарам", "По аптекам" };
    [ObservableProperty] private int _selectedReportIndex;

    public string[] AiFormats { get; } = { "Word", "Excel" };
    [ObservableProperty] private int _selectedAiFormat;
    [ObservableProperty] private string _aiPrompt = "";

    [ObservableProperty] private string _totals = "";
    [ObservableProperty] private string? _status;
    [ObservableProperty] private bool _busy;
    [ObservableProperty] private bool _aiBusy;

    public ReportsViewModel()
    {
        _api.SetToken(Session.Current.Token);
        if (Session.Current.IsAuthenticated)
            _ = BuildAsync();   // авто-загрузка за последний месяц при открытии
    }

    partial void OnSelectedReportIndexChanged(int value) => Render();

    [RelayCommand]
    private async Task BuildAsync()
    {
        Status = null;
        try
        {
            Busy = true;
            _lines = await _api.GetBuyerReportAsync(DateFrom.DateTime.Date, DateTo.DateTime.Date);
            Render();
            if (_lines.Count == 0) Status = "За выбранный период заказов нет.";
        }
        catch (Exception ex) { Status = ex.Message; }
        finally { Busy = false; }
    }

    [RelayCommand]
    private async Task GenerateAiAsync()
    {
        Status = null;
        if (string.IsNullOrWhiteSpace(AiPrompt)) { Status = "Введите запрос для ИИ."; return; }
        try
        {
            AiBusy = true;
            var fmt = SelectedAiFormat == 1 ? "xlsx" : "docx";
            var res = await _api.GenerateAiReportAsync(AiPrompt.Trim(), fmt);
            var dir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            var safe = string.Join("_", res.FileName.Split(Path.GetInvalidFileNameChars()));
            var path = Path.Combine(dir, safe);
            if (File.Exists(path))
            {
                var name = Path.GetFileNameWithoutExtension(safe);
                var ext = Path.GetExtension(safe);
                path = Path.Combine(dir, $"{name}_{DateTime.Now:yyyyMMdd_HHmmss}{ext}");
            }
            File.WriteAllBytes(path, res.Content);
            Status = "Отчёт сохранён: " + path;
            OpenFile(path);
        }
        catch (Exception ex) { Status = ex.Message; }
        finally { AiBusy = false; }
    }

    private void Render()
    {
        Columns.Clear();
        Rows.Clear();

        var (cols, rows) = Aggregate(_lines, SelectedReportIndex);
        foreach (var c in cols) Columns.Add(c);
        foreach (var r in rows) Rows.Add(new ReportRow(r));

        var orders = _lines.Select(l => l.OrderId).Distinct().Count();
        var sum = _lines.Sum(l => l.Sum);
        Totals = $"Заказов: {orders}    Позиций: {_lines.Count}    Сумма: {sum:N2}";
        ColumnsChanged?.Invoke();
    }

    private static (List<ReportColumn> cols, List<string[]> rows) Aggregate(List<BuyerReportLineDto> lines, int type)
    {
        string N2(decimal d) => d.ToString("N2");
        string N3(decimal d) => d.ToString("N3");
        string D(DateTime? dt) => dt?.ToLocalTime().ToString("dd.MM.yyyy") ?? "";

        switch (type)
        {
            case 1: // По поставщикам
            {
                var cols = new List<ReportColumn>
                {
                    new() { Header = "Поставщик", Stretch = true },
                    new() { Header = "Заказов", Numeric = true, Weight = 90 },
                    new() { Header = "Позиций", Numeric = true, Weight = 90 },
                    new() { Header = "Сумма", Numeric = true, Weight = 120 },
                };
                var rows = lines.GroupBy(l => string.IsNullOrWhiteSpace(l.Supplier) ? "(не указан)" : l.Supplier!)
                    .OrderByDescending(g => g.Sum(x => x.Sum))
                    .Select(g => new[] { g.Key, g.Select(x => x.OrderId).Distinct().Count().ToString(),
                                         g.Count().ToString(), N2(g.Sum(x => x.Sum)) }).ToList();
                return (cols, rows);
            }
            case 2: // По товарам
            {
                var cols = new List<ReportColumn>
                {
                    new() { Header = "Товар", Stretch = true },
                    new() { Header = "Код", Weight = 100 },
                    new() { Header = "Кол-во", Numeric = true, Weight = 100 },
                    new() { Header = "Сумма", Numeric = true, Weight = 120 },
                };
                var rows = lines.GroupBy(l => ((l.ItemName ?? "").Trim() + "|" + (l.ItemCode ?? "")))
                    .OrderByDescending(g => g.Sum(x => x.Sum))
                    .Select(g => { var f = g.First(); return new[] { f.ItemName ?? "", f.ItemCode ?? "",
                                         N3(g.Sum(x => x.Qty)), N2(g.Sum(x => x.Sum)) }; }).ToList();
                return (cols, rows);
            }
            case 3: // По аптекам
            {
                var cols = new List<ReportColumn>
                {
                    new() { Header = "Аптека", Stretch = true },
                    new() { Header = "Заказов", Numeric = true, Weight = 90 },
                    new() { Header = "Позиций", Numeric = true, Weight = 90 },
                    new() { Header = "Сумма", Numeric = true, Weight = 120 },
                };
                var rows = lines.GroupBy(l => string.IsNullOrWhiteSpace(l.Location) ? "(не указана)" : l.Location!)
                    .OrderByDescending(g => g.Sum(x => x.Sum))
                    .Select(g => new[] { g.Key, g.Select(x => x.OrderId).Distinct().Count().ToString(),
                                         g.Count().ToString(), N2(g.Sum(x => x.Sum)) }).ToList();
                return (cols, rows);
            }
            default: // Мои заказы
            {
                var cols = new List<ReportColumn>
                {
                    new() { Header = "Дата", Weight = 105 },
                    new() { Header = "Номер", Weight = 138 },
                    new() { Header = "Поставщик", Weight = 150 },
                    new() { Header = "Аптека", Stretch = true },
                    new() { Header = "Позиций", Numeric = true, Weight = 95 },
                    new() { Header = "Сумма", Numeric = true, Weight = 125 },
                    new() { Header = "Статус", Weight = 100 },
                };
                var rows = lines.GroupBy(l => l.OrderId)
                    .OrderByDescending(g => g.First().OrderDate ?? DateTime.MinValue)
                    .Select(g =>
                    {
                        var f = g.First();
                        var sup = string.Join(", ", g.Select(x => x.Supplier).Where(s => !string.IsNullOrWhiteSpace(s)).Distinct());
                        return new[] { D(f.OrderDate), f.GlobalSign ?? "", sup, f.Location ?? "",
                                       g.Count().ToString(), N2(g.Sum(x => x.Sum)), f.Status ?? "" };
                    }).ToList();
                return (cols, rows);
            }
        }
    }

    private static void OpenFile(string path)
    {
        try
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                Process.Start(new ProcessStartInfo { FileName = path, UseShellExecute = true });
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                Process.Start("open", $"\"{path}\"");
            else
                Process.Start("xdg-open", $"\"{path}\"");
        }
        catch { /* открыть не удалось — путь показан в статусе */ }
    }
}
