using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
using GCHR.Model.Konto;

namespace GCHR.Control.Tasks
{
    class Verarbeitung : Task
    {
        public Verarbeitung(int id, string name)
            : base(id, name) { }

        protected override void AufgabeAusfuehren()
        {
            var konten = Data.GetKonten();
            // if (Data.ImportdatenSichern) KontenXmlSpeichern(konten);
            Data.SetKonten(KontenrahmenUebersetzen(konten));
            KontenXmlSpeichern(_zielKonten.Values.ToList());
            Data.AufSusaStatWarten.Set();
        }

        private readonly IDictionary<string, HaendlerKonto> _zielKonten = new SortedDictionary<string, HaendlerKonto>();

        private readonly IDictionary<string, string> _nichtZugeordnet = new SortedDictionary<string, string>();
        private readonly IDictionary<string, string> _nichtImKontenrahmen = new SortedDictionary<string, string>();

        private readonly HaendlerKonto _debugKontoKontenrahmen = new HaendlerKonto(KontoTypen.Debug) { Kontonummer = "00000000_1", Bezeichnung = "nicht im Kontenrahmen" };
        private readonly HaendlerKonto _debugKontoUebersetzung = new HaendlerKonto(KontoTypen.Debug) { Kontonummer = "00000000_2", Bezeichnung = "Uebersetzung fehlt" };

        private List<HaendlerKonto> KontenrahmenUebersetzen(IEnumerable<HaendlerKonto> kontenimport)
        {
            Data.KontoOhneUebersetzungUebernehmen = Config.KontoOhneUebersetzungUebernehmen;

            foreach (var aktKonto in kontenimport)
            {
                KontoUebersetzen(aktKonto);
            }

            if (Data.KeinJahresabschluss)
            {
                _zielKonten.Add(Data.JahresergebnisKonto.KontonummerFormatiert, Data.JahresergebnisKonto);
            }

            ReportNichtZugeordnet();
            ReportNichtImKontenrahmen();

            return _zielKonten.Values.ToList();
        }

        private void KontoUebersetzen(HaendlerKonto aktKonto)
        {
            var kontonummer = SplitKontoVerarbeiten(Data.KontoUebersetzen(aktKonto), aktKonto.Marke);

            if (kontonummer == null)
            {
                if (aktKonto.Summe != 0.0m && !_nichtZugeordnet.ContainsKey(aktKonto.KontoTyp + aktKonto.Kontonummer))
                {
                    _nichtZugeordnet.Add(aktKonto.KontoTyp + aktKonto.Kontonummer, DebugInfo(aktKonto));
                }
                _debugKontoUebersetzung.KontoZuordnen(aktKonto);
                return;
            }

            var ziel = Data.KontoAusKontenrahmen(kontonummer, aktKonto);

            if (ziel == null)
            {
                if (aktKonto.Summe != 0.0m && !_nichtImKontenrahmen.ContainsKey(kontonummer))
                {
                    _nichtImKontenrahmen.Add(kontonummer, DebugInfo(kontonummer, aktKonto));
                }
                _debugKontoKontenrahmen.KontoZuordnen(aktKonto);
                return;
            }

            if (!_zielKonten.ContainsKey(ziel.KontonummerFormatiert))
            {
                _zielKonten.Add(ziel.KontonummerFormatiert, ziel);
            }
            else
            {
                ziel = _zielKonten[ziel.KontonummerFormatiert];
            }
            ziel.KontoZuordnen(aktKonto);
        }

        private string SplitKontoVerarbeiten(string konto, string marke)
        {
            if (konto == null || !konto.Contains(",")) return konto;

            if (marke.Equals(Config.Hauptmarke))
            {
                return konto.Split(',')[0];
            }
            return konto.Split(',')[1];
        }




        private void ReportNichtImKontenrahmen()
        {
            if (_nichtImKontenrahmen.Count <= 0) return;
            ReportProgress(60, "Es fehlen " + _nichtImKontenrahmen.Count + " Konten im Kontenrahmen.");
            Logger.Progress("Fehlende Konten im Kontenrahmen (" + _nichtImKontenrahmen.Count + "): " + Environment.NewLine + String.Join(Environment.NewLine, _nichtImKontenrahmen.Values.ToArray()));
            _zielKonten.Add(_debugKontoKontenrahmen.Kontonummer, _debugKontoKontenrahmen);
        }

        private void ReportNichtZugeordnet()
        {
            if (_nichtZugeordnet.Count <= 0) return;
            ReportProgress(50, "Es konnten " + _nichtZugeordnet.Count + " Konten nicht zugeordnet werden." + Environment.NewLine);
            Logger.Progress("Nicht zugeordnete Konten (" + _nichtZugeordnet.Count + "): " + Environment.NewLine + String.Join(Environment.NewLine, _nichtZugeordnet.Values.ToArray()));
            _zielKonten.Add(_debugKontoUebersetzung.Kontonummer, _debugKontoUebersetzung);
        }

        private static string DebugInfo(string kontonummer, HaendlerKonto aktKonto)
        {
            return String.Format("{0} (Typ: {1}, Kontoart: {4}, Summe (M:{5}, B:{6}): {2}, Anzahl Perioden: {3})",
                                    kontonummer, aktKonto.KontoTyp, aktKonto.Summe, aktKonto.ZugeordneteSaldi.Count, aktKonto.Kontoart, aktKonto.Marke, aktKonto.Betrieb);
        }

        private static string DebugInfo(HaendlerKonto aktKonto)
        {
            return DebugInfo(aktKonto.Kontonummer, aktKonto);
        }



        private static void KontenXmlSpeichern(List<HaendlerKonto> konten)
        {
            var serializer = new XmlSerializer(typeof(Konten));
            using (var stream = File.CreateText("logs\\Zuordnung.xml"))
            {
                serializer.Serialize(stream, new Konten { Kontenliste = konten });
            }
        }
    }
}