using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using XMLParser.Model;

namespace XMLParser.Functions
{
    public static class Calculate 
    {
        public static string CalculateWaterBariedAsString(List<KanalObjekt> inspektionen)
        {
            List<KanalObjekt> barieded = inspektionen.FindAll(x => x.Inspektionsdaten.OptischeInspektion.Wasserhaltung != EWasserhaltung.NONE);
            List<int> DistinctDurchmesser = barieded.Select(s => s.Inspektionsdaten.OptischeInspektion.Rohrleitung.Grunddaten.Profilbreite).Distinct().ToList();

            string result = "#ANZAHLGESAMT# Dichtkissen gesetzt. ";
            int counter = 0;

            foreach(int durchmesser in DistinctDurchmesser)
            {
                List<KanalObjekt> abgesperrt = barieded.FindAll(x => x.Inspektionsdaten.OptischeInspektion.Rohrleitung.Grunddaten.Profilbreite.Equals(durchmesser));
                result = string.Format("{0} DN{1} in Schacht", result, durchmesser);
                foreach(KanalObjekt objekt in abgesperrt)
                {
                    result = string.Format(" {0} {1} ", result, objekt.Stammdaten.Objektbezeichnung);
                    counter++;
                }
            }
            result = result.Replace("#ANZAHLGESAMT#",counter.ToString());
            return result;
        }
        public static Dictionary<ECalculatedResult,decimal> CalculateStreet(List<KanalObjekt> inspektionen)
        {
            Dictionary<ECalculatedResult,decimal> result = new Dictionary<ECalculatedResult, decimal>();
            
            List<KanalObjekt> Anschlussleitungen = inspektionen.FindAll(x => x.Inspektionsdaten.Anlagentyp.Equals(EAnlagetyp.Anschlussleitung));
            List<KanalObjekt> SEs = Anschlussleitungen.FindAll(x => x.Stammdaten.Knoten != null && x.Stammdaten.Knoten.Anschlusspunkt != null && x.Stammdaten.Knoten.Anschlusspunkt.Punktkennung.Equals("SE"));
            List<KanalObjekt> SOs = Anschlussleitungen.FindAll(x => x.Stammdaten.Knoten != null && x.Stammdaten.Knoten.Anschlusspunkt != null && !x.Stammdaten.Knoten.Anschlusspunkt.Punktkennung.Equals("SE"));
            
            foreach(KanalObjekt s in SEs) {
                Anschlussleitungen.Remove(s);
            }
            foreach(KanalObjekt s in SOs) {
                Anschlussleitungen.Remove(s);
            }
            SOs.AddRange(Anschlussleitungen);
            
            decimal SEOverlength = 0.0m;
            decimal SOOverlength = 0.0m;

            SEs.ForEach(x => {
                decimal length = x.Inspektionsdaten.OptischeInspektion.Rohrleitung.Inspektionslaenge;
                if(length > 5.0m) SEOverlength += length - 5.0m;
            });
            SOs.ForEach(x => {
                decimal length = x.Inspektionsdaten.OptischeInspektion.Rohrleitung.Inspektionslaenge;
                if(length > 7.0m) SOOverlength += length - 7.0m;
            });
            
            result.Add(ECalculatedResult.SONSTIGEANZAHL,SOs.Count);
            result.Add(ECalculatedResult.SONSTIGELAENGEZULAGEMETER,SOOverlength);
            

            result.Add(ECalculatedResult.STRASSENABLAUFANZAHL,SEs.Count);
            result.Add(ECalculatedResult.STRASSENABLAUFLAENGEZULAGEMETER,SEOverlength);
            
            decimal HauptkanalLaenge =0.0m;

            List<int> ranges = new List<int>()
            {
                250,
                400,
                600,
                800,
                1000,
                int.MaxValue
            };
            var rangePairs = ranges.Select((r,i)=> new {Range = r,Index = i}).ToList();
            
            IEnumerable<IGrouping<int, KanalObjekt>> groupedInspektion = inspektionen
                            .FindAll(s => s.Inspektionsdaten.Anlagentyp.Equals(EAnlagetyp.Haltung))
                            .OrderBy(a => a.Inspektionsdaten.OptischeInspektion.Rohrleitung.Grunddaten.Profilbreite)
                            .GroupBy(x => rangePairs.FirstOrDefault(r => r.Range >= x.Inspektionsdaten.OptischeInspektion.Rohrleitung.Grunddaten.Profilbreite)?.Index ?? -1)
                            .ToList();
            var t = groupedInspektion.ToList();
            decimal length = 0.0m;
            int counter = 0;
            foreach(IGrouping<int,KanalObjekt> v in t)
            {
                length = 0.0m;
                List<InspizierteAbwassertechnischeAnlage> d = t[counter].Select(group => group.Inspektionsdaten).ToList();
                d.ForEach(g => length += g.OptischeInspektion.Rohrleitung.Inspektionslaenge);
                switch(v.Key)
                {
                    case 0: result.Add(ECalculatedResult.DN150DN250,length); break;
                    case 1: result.Add(ECalculatedResult.DN300DN400,length); break;
                    case 2: result.Add(ECalculatedResult.DN450DN600,length); break;
                    case 3: result.Add(ECalculatedResult.DN650DN800,length); break;
                    case 4: result.Add(ECalculatedResult.DN850DN1000,length); break;
                    default: throw new Exception(v.Key.ToString());
                }
                HauptkanalLaenge += length;
                counter++;
            }

            result.Add(ECalculatedResult.GESAMTHAUPTKANAL,HauptkanalLaenge);

            return result;
        }
        public static Dictionary<ECalculatedResult,decimal> CalculateDay(List<KanalObjekt> inspektionen)
        {
            Dictionary<ECalculatedResult,decimal> result = new Dictionary<ECalculatedResult, decimal>();
            decimal HauptkanalLaenge =0.0m;
            
            inspektionen
                .FindAll(s => s.Inspektionsdaten.Anlagentyp.Equals(EAnlagetyp.Haltung))
                .ForEach(g => HauptkanalLaenge += g.Inspektionsdaten.OptischeInspektion.Rohrleitung.Inspektionslaenge);
            result.Add(ECalculatedResult.GESAMTHAUPTKANAL,HauptkanalLaenge);
            
            List<KanalObjekt> Anschlussleitungen = inspektionen.FindAll(x => x.Inspektionsdaten.Anlagentyp.Equals(EAnlagetyp.Anschlussleitung));
            List<KanalObjekt> SEs = Anschlussleitungen.FindAll(x => x.Stammdaten.Knoten != null && x.Stammdaten.Knoten.Anschlusspunkt != null && x.Stammdaten.Knoten.Anschlusspunkt.Punktkennung.Equals("SE"));
            List<KanalObjekt> SOs = Anschlussleitungen.FindAll(x => x.Stammdaten.Knoten != null && x.Stammdaten.Knoten.Anschlusspunkt != null && !x.Stammdaten.Knoten.Anschlusspunkt.Punktkennung.Equals("SE"));
            
            foreach(KanalObjekt s in SEs) {
                Anschlussleitungen.Remove(s);
            }
            foreach(KanalObjekt s in SOs) {
                Anschlussleitungen.Remove(s);
            }

            SOs.AddRange(Anschlussleitungen);

            result.Add(ECalculatedResult.STRASSENABLAUFANZAHL,SEs.Count);
            result.Add(ECalculatedResult.SONSTIGEANZAHL,SOs.Count);
            
            decimal SEPauschal = 34.00m * SEs.Count;
            decimal SOPauschal = 45.00m * SOs.Count;
            decimal HauptkanalPreis = 1.60m * HauptkanalLaenge;

            result.Add(ECalculatedResult.STRASSENABLAUFUMSATZ,SEPauschal);
            result.Add(ECalculatedResult.SONSTIGEUMSATZ,SOPauschal);
            result.Add(ECalculatedResult.HAUPTKANALUMSATZ,HauptkanalPreis);


            
            decimal SEOverlength = 0.0m;
            decimal SOOverlength = 0.0m;

            SEs.ForEach(x => {
                decimal length = x.Inspektionsdaten.OptischeInspektion.Rohrleitung.Inspektionslaenge;
                if(length > 5.0m) SEOverlength += length - 5.0m;
            });
            SOs.ForEach(x => {
                decimal length = x.Inspektionsdaten.OptischeInspektion.Rohrleitung.Inspektionslaenge;
                if(length > 7.0m) SOOverlength += length - 7.0m;
            });
            
            decimal LeitungsOverlengthPreis = (SEOverlength + SOOverlength) * 2.4m;
            result.Add(ECalculatedResult.STRASSENABLAUFLAENGEZULAGEMETER,SEOverlength);
            result.Add(ECalculatedResult.SONSTIGELAENGEZULAGEMETER,SOOverlength);
            result.Add(ECalculatedResult.LAENGEZULAGEUMSATZ,LeitungsOverlengthPreis);
            result.Add(ECalculatedResult.GESAMTUMSATZ,(LeitungsOverlengthPreis + HauptkanalPreis + SEPauschal + SOPauschal));
            return result;
        }
    }
}
