using Elwig.Models.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Nodes;

namespace Elwig.Helpers.Billing {
    public class EditBillingData : BillingData {

        protected readonly IEnumerable<string> AttributeVariants;

        public EditBillingData(JsonObject data, IEnumerable<string> attributeVariants) :
            base(data) {
            AttributeVariants = attributeVariants;
        }

        public static EditBillingData FromJson(string json, IEnumerable<string> attributeVariants) {
            return new(ParseJson(json), attributeVariants);
        }

        public IEnumerable<GraphEntry> GetPaymentGraphEntries(AppDbContext context, Season season) {
            Dictionary<int, List<string>> dict1 = [];
            Dictionary<decimal, List<string>> dict2 = [];
            var p = GetPaymentEntry();
            if (p is JsonObject paymentObj) {
                foreach (var (selector, node) in paymentObj) {
                    var val = node?.AsValue();
                    if (val == null) {
                        continue;
                    } else if (val.TryGetValue<decimal>(out var price)) {
                        if (!dict2.ContainsKey(price)) dict2[price] = [];
                        dict2[price].Add(selector);
                    } else if (val.TryGetValue<string>(out var curve)) {
                        var idx = int.Parse(curve.Split(":")[1] ?? "0");
                        if (!dict1.ContainsKey(idx)) dict1[idx] = [];
                        dict1[idx].Add(selector);
                    }
                }
            } else if (p is JsonValue paymentVal) {
                if (paymentVal.TryGetValue<decimal>(out var price)) {
                    if (!dict2.ContainsKey(price)) dict2[price] = [];
                    dict2[price].Add("default");
                } else if (paymentVal.TryGetValue<string>(out var curve)) {
                    var idx = int.Parse(curve.Split(":")[1] ?? "0");
                    if (!dict1.ContainsKey(idx)) dict1[idx] = [];
                    dict1[idx].Add("default");
                }

            }

            var virtOffset = dict1.Count > 0 ? dict1.Max(e => e.Key) + 1 : 1;
            Dictionary<int, Curve> curves = GetCurves();
            decimal[] virtCurves = [.. dict2.Keys.Order()];
            for (int i = 0; i < virtCurves.Length; i++) {
                var idx = virtCurves[i];
                dict1[i + virtOffset] = dict2[idx];
                curves[i + virtOffset] = new Curve(CurveMode.Oe, new() { { 73, idx } }, null);
            }

            Dictionary<int, List<string>> dict3 = curves.ToDictionary(c => c.Key, _ => new List<string>());
            foreach (var (selector, value) in GetSelection(p, AttributeVariants)) {
                int? idx = null;
                if (value.TryGetValue<decimal>(out var val)) {
                    idx = Array.IndexOf(virtCurves, val) + virtOffset;
                } else if (value.TryGetValue<string>(out var str)) {
                    idx = int.Parse(str.Split(":")[1]);
                }
                if (idx != null)
                    dict3[(int)idx].Add(selector);
            }

            var vars = context.WineVarieties.ToDictionary(v => v.SortId, v => v);
            var attrs = context.WineAttributes.ToDictionary(a => a.AttrId, a => a);

            return dict3
                .Select(e => new GraphEntry(e.Key, season.Precision, curves[e.Key], e.Value
                    .Select(s => new ContractSelection(vars[s[..2]], s.Length > 2 ? attrs[s[2..]] : null))
                    .ToList()))
                .ToList();
        }

        public IEnumerable<GraphEntry> GetQualityGraphEntries(AppDbContext context, Season season) {
            Dictionary<int, List<string>> dict1 = [];
            Dictionary<decimal, List<string>> dict2 = [];
            foreach (var (qualid, q) in GetQualityEntry() ?? []) {
                if (q is JsonObject qualityObj) {
                    foreach (var (selector, node) in qualityObj) {
                        var val = node?.AsValue();
                        if (val == null) {
                            continue;
                        } else if (val.TryGetValue<decimal>(out var price)) {
                            if (!dict2.ContainsKey(price)) dict2[price] = [];
                            dict2[price].Add(selector);
                        } else if (val.TryGetValue<string>(out var curve)) {
                            var idx = int.Parse(curve.Split(":")[1] ?? "0");
                            if (!dict1.ContainsKey(idx)) dict1[idx] = [];
                            dict1[idx].Add(selector);
                        }
                    }
                } else if (q is JsonValue qualityVal) {
                    var idx = qualityVal.GetValue<decimal>();
                    if (!dict2.ContainsKey(idx)) dict2[idx] = [];
                    dict2[idx].Add($"{qualid}/");
                }
            }

            // TODO

            List<GraphEntry> list = [];

            return list;
        }
    }
}