using System;
using System.Collections.Generic;
using System.Linq;

namespace Elwig.Helpers.Billing {
    public class GraphEntry {

        public const int MinX = 50;
        public const int MinXGeb = 73;
        public const int MaxX = 120;

        public int Id { get; set; }
        public BillingData.CurveMode Mode { get; set; }
        public bool Abgewertet { get; set; }

        public Graph DataGraph { get; set; }
        public Graph? GebundenGraph { get; set; }
        public double? GebundenFlatBonus {
            get {
                try {
                    var val = GebundenGraph?.DataX.Zip(GebundenGraph.DataY)
                        .Select(e => Math.Round(e.Second - DataGraph.GetPriceAtOe(e.First), Precision))
                        .Distinct()
                        .Single();
                    return (val == 0) ? null : val;
                } catch {
                    return null;
                }
            }
            set {
                if (value is not double v) return;
                var values = Enumerable.Range(MinXGeb, MaxX - MinXGeb + 1)
                    .Select(i => Math.Round(DataGraph.GetPriceAtOe(i) + v, Precision))
                    .ToArray();
                GebundenGraph = new Graph(values, Precision, MinXGeb, MaxX);
            }
        }

        public List<Varibute> Vaributes { get; set; }
        public string VaributeStringSimple => (Abgewertet ? "Abgew.: " : "") + (Vaributes.Count != 0 ? (Vaributes.Count >= 25 ? "Restliche Sorten" : string.Join(", ", Vaributes.Select(c => c.Listing))) : "-");
        public string VaributeString => Vaributes.Count != 0 ? string.Join("\n", Vaributes.Select(c => c.FullName)) : "-";
        public string VaributeStringChange => (Abgewertet ? "A." : "") + string.Join(",", Vaributes.Select(c => c.Listing));
        private readonly int Precision;

        public GraphEntry(int id, int precision, BillingData.CurveMode mode) {
            Id = id;
            Precision = precision;
            Mode = mode;
            DataGraph = new Graph(precision, MinX, MaxX); ;
            Vaributes = [];
        }

        public GraphEntry(int id, int precision, BillingData.CurveMode mode, Dictionary<double, decimal> data, Dictionary<double, decimal>? gebunden) :
            this(id, precision, mode) {
            DataGraph = new Graph(data, precision, MinX, MaxX);
            if (gebunden != null) GebundenGraph = new Graph(gebunden, precision, MinXGeb, MaxX);
        }

        public GraphEntry(int id, int precision, BillingData.Curve curve, List<Varibute> vaributes) :
            this(id, precision, curve.Mode) {
            DataGraph = new Graph(curve.Normal, precision, MinX, MaxX);
            if (curve.Gebunden != null)
                GebundenGraph = new Graph(curve.Gebunden, precision, MinXGeb, MaxX);
            Vaributes = vaributes;
        }

        private GraphEntry(int id, int precision, BillingData.CurveMode mode, Graph dataGraph, Graph? gebundenGraph, List<Varibute> vaributes) {
            Id = id;
            Precision = precision;
            Mode = mode;
            DataGraph = dataGraph;
            GebundenGraph = gebundenGraph;
            Vaributes = vaributes;
        }

        public void AddGebundenGraph() {
            GebundenGraph ??= new Graph(Precision, MinXGeb, MaxX);
        }

        public void RemoveGebundenGraph() {
            GebundenGraph = null;
        }

        public GraphEntry Copy(int id) {
            return new GraphEntry(id, Precision, Mode, (Graph)DataGraph.Clone(), (Graph?)GebundenGraph?.Clone(), []);
        }
    }
}