using Adaptation.Eaf.Management.ConfigurationData.CellAutomation;
using Adaptation.Ifx.Eaf.EquipmentConnector.File.Configuration;
using Adaptation.Shared;
using Adaptation.Shared.Duplicator;
using Adaptation.Shared.Methods;
using Infineon.Monitoring.MonA;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text.Json;
using System.Threading;

namespace Adaptation.FileHandlers.Dummy;

public class FileRead : Shared.FileRead, IFileRead
{

    private readonly Timer _Timer;
    private int _LastDummyRunIndex;
    private readonly string[] _CellNames;

    public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, bool useCyclicalForDescription, bool isEAFHosted) :
        base(new Description(), false, smtp, fileParameter, cellInstanceName, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, useCyclicalForDescription, isEAFHosted)
    {
        _MinFileLength = 10;
        _NullData = string.Empty;
        _Logistics = new Logistics(this);
        if (_FileParameter is null)
            throw new Exception(cellInstanceConnectionName);
        if (_ModelObjectParameterDefinitions is null)
            throw new Exception(cellInstanceConnectionName);
        if (!_IsDuplicator)
            throw new Exception(cellInstanceConnectionName);
        _LastDummyRunIndex = -1;
        List<string> cellNames = new();
        _Timer = new Timer(Callback, null, Timeout.Infinite, Timeout.Infinite);
        ModelObjectParameterDefinition[] cellInstanceCollection = GetProperties(cellInstanceConnectionName, modelObjectParameters, "CellInstance.", ".Alias");
        foreach (ModelObjectParameterDefinition modelObjectParameterDefinition in cellInstanceCollection)
            cellNames.Add(modelObjectParameterDefinition.Name.Split('.')[1]);
        _CellNames = cellNames.ToArray();
        if (Debugger.IsAttached || fileConnectorConfiguration.PreProcessingMode == FileConnectorConfiguration.PreProcessingModeEnum.Process)
            Callback(null);
        else
        {
            TimeSpan timeSpan = new(DateTime.Now.AddSeconds(_FileConnectorConfiguration.FileScanningIntervalInSeconds.Value).Ticks - DateTime.Now.Ticks);
            _ = _Timer.Change((long)timeSpan.TotalMilliseconds, Timeout.Infinite);
        }
    }

    void IFileRead.Move(Tuple<string, Test[], JsonElement[], List<FileInfo>> extractResults, Exception exception) => Move(extractResults, exception);

    void IFileRead.WaitForThread() => WaitForThread(thread: null, threadExceptions: null);

    string IFileRead.GetEventDescription()
    {
        string result = _Description.GetEventDescription();
        return result;
    }

    List<string> IFileRead.GetHeaderNames()
    {
        List<string> results = _Description.GetHeaderNames();
        return results;
    }

    string[] IFileRead.Move(Tuple<string, Test[], JsonElement[], List<FileInfo>> extractResults, string to, string from, string resolvedFileLocation, Exception exception)
    {
        string[] results = Move(extractResults, to, from, resolvedFileLocation, exception);
        return results;
    }

    JsonProperty[] IFileRead.GetDefault()
    {
        JsonProperty[] results = _Description.GetDefault(this, _Logistics);
        return results;
    }

    Dictionary<string, string> IFileRead.GetDisplayNamesJsonElement()
    {
        Dictionary<string, string> results = _Description.GetDisplayNamesJsonElement(this);
        return results;
    }

    List<IDescription> IFileRead.GetDescriptions(IFileRead fileRead, List<Test> tests, IProcessData processData)
    {
        List<IDescription> results = _Description.GetDescriptions(fileRead, _Logistics, tests, processData);
        return results;
    }

    Tuple<string, Test[], JsonElement[], List<FileInfo>> IFileRead.GetExtractResult(string reportFullPath, string eventName) => throw new Exception(string.Concat("See ", nameof(CallbackFileExists)));

    Tuple<string, Test[], JsonElement[], List<FileInfo>> IFileRead.ReExtract() => throw new Exception(string.Concat("See ", nameof(CallbackFileExists)));

    void IFileRead.CheckTests(Test[] tests, bool extra)
    {
        if (_Description is not Description)
            throw new Exception();
    }

    private void CallbackInProcessCleared(string sourceArchiveFile, string traceDummyFile, string targetFileLocation, string monARessource, string inProcessDirectory, long sequence, bool warning)
    {
        const string site = "sjc";
        string stateName = string.Concat("Dummy_", _EventName);
        const string monInURL = "http://moninhttp.sjc.infineon.com/input/text";
        MonIn monIn = MonIn.GetInstance(monInURL);
        try
        {
            if (warning)
            {
                File.AppendAllLines(traceDummyFile, new string[] { site, monARessource, stateName, State.Warning.ToString() });
                _ = monIn.SendStatus(site, monARessource, stateName, State.Warning);
                for (int i = 1; i < 12; i++)
                    Thread.Sleep(500);
            }
            ZipFile.ExtractToDirectory(sourceArchiveFile, inProcessDirectory);
            string[] files = Directory.GetFiles(inProcessDirectory, "*", SearchOption.TopDirectoryOnly);
            if (files.Length > 250)
                throw new Exception("Safety net!");
            foreach (string file in files)
                File.SetLastWriteTime(file, new DateTime(sequence));
            if (!_FileConnectorConfiguration.IncludeSubDirectories.Value)
            {
                foreach (string file in files)
                    File.Move(file, Path.Combine(targetFileLocation, Path.GetFileName(file)));
            }
            else
            {
                string[] directories = Directory.GetDirectories(inProcessDirectory, "*", SearchOption.AllDirectories);
                foreach (string directory in directories)
                    _ = Directory.CreateDirectory(string.Concat(targetFileLocation, directory.Substring(inProcessDirectory.Length)));
                foreach (string file in files)
                    File.Move(file, string.Concat(targetFileLocation, file.Substring(inProcessDirectory.Length)));
            }
            File.AppendAllLines(traceDummyFile, new string[] { site, monARessource, stateName, State.Ok.ToString() });
            _ = monIn.SendStatus(site, monARessource, stateName, State.Ok);
        }
        catch (Exception exception)
        {
            string subject = string.Concat("Exception:", _CellInstanceConnectionName);
            string body = string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace);
            try
            { _SMTP.SendHighPriorityEmailMessage(subject, body); }
            catch (Exception) { }
            File.AppendAllLines(traceDummyFile, new string[] { site, monARessource, stateName, State.Critical.ToString(), exception.Message, exception.StackTrace });
            _ = monIn.SendStatus(site, monARessource, stateName, State.Critical);
        }
    }

    private void CallbackFileExists(string sourceArchiveFile, string traceDummyFile, string targetFileLocation, string monARessource, long sequence)
    {
        string[] files;
        bool warning = false;
        if (!_DummyRuns.ContainsKey(monARessource))
            _DummyRuns.Add(monARessource, new List<long>());
        if (!_DummyRuns[monARessource].Contains(sequence))
            _DummyRuns[monARessource].Add(sequence);
        File.AppendAllLines(traceDummyFile, new string[] { sourceArchiveFile });
        string inProcessDirectory = Path.Combine(_ProgressPath, "Dummy In-Process", sequence.ToString());
        if (!Directory.Exists(inProcessDirectory))
            _ = Directory.CreateDirectory(inProcessDirectory);
        files = Directory.GetFiles(inProcessDirectory, "*", SearchOption.AllDirectories);
        if (files.Any())
        {
            if (files.Length > 250)
                throw new Exception("Safety net!");
            try
            {
                foreach (string file in files)
                    File.Delete(file);
            }
            catch (Exception) { }
        }
        if (_FileConnectorConfiguration.IncludeSubDirectories.Value)
            files = Directory.GetFiles(targetFileLocation, "*", SearchOption.AllDirectories);
        else
            files = Directory.GetFiles(targetFileLocation, "*", SearchOption.TopDirectoryOnly);
        foreach (string file in files)
        {
            if (new FileInfo(file).LastWriteTime.Ticks == sequence)
            {
                warning = true;
                break;
            }
        }
        CallbackInProcessCleared(sourceArchiveFile, traceDummyFile, targetFileLocation, monARessource, inProcessDirectory, sequence, warning);
    }

    private string GetCellName(string pathSegment)
    {
        string result = string.Empty;
        foreach (string cellName in _CellNames)
        {
            if (pathSegment.ToLower().Contains(cellName.ToLower()))
            {
                result = cellName;
                break;
            }
        }
        if (string.IsNullOrEmpty(result))
        {
            int count;
            List<(string CellName, int Count)> cellNames = new();
            foreach (string cellName in _CellNames)
            {
                count = 0;
                foreach (char @char in cellName.ToLower())
                    count += pathSegment.Length - pathSegment.ToLower().Replace(@char.ToString(), string.Empty).Length;
                cellNames.Add(new(cellName, count));
            }
            result = (from l in cellNames orderby l.CellName.Length, l.Count descending select l.CellName).First();
        }
        return result;
    }

    private void Callback(object state)
    {
        try
        {
            string pathSegment;
            string monARessource;
            DateTime dateTime = DateTime.Now;
            if (!_FileConnectorConfiguration.TargetFileLocation.Contains(_FileConnectorConfiguration.SourceFileLocation))
                throw new Exception("Target must start with source!");
            bool check = dateTime.Hour > 7 && dateTime.Hour < 18 && dateTime.DayOfWeek != DayOfWeek.Sunday && dateTime.DayOfWeek != DayOfWeek.Saturday;
            if (!_IsEAFHosted || check)
            {
                string checkSegment;
                string checkDirectory;
                string sourceFileFilter;
                string sourceArchiveFile;
                string sourceFileLocation;
                string weekOfYear = _Calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00");
                string traceDummyDirectory = Path.Combine(Path.GetPathRoot(_TracePath), "TracesDummy", _CellInstanceName, "Source", $"{dateTime:yyyy}___Week_{weekOfYear}");
                if (!Directory.Exists(traceDummyDirectory))
                    _ = Directory.CreateDirectory(traceDummyDirectory);
                string traceDummyFile = Path.Combine(traceDummyDirectory, $"{dateTime.Ticks} - {_CellInstanceName}.txt");
                File.AppendAllText(traceDummyFile, string.Empty);
                if (_FileConnectorConfiguration.SourceFileLocation.EndsWith("\\"))
                    sourceFileLocation = _FileConnectorConfiguration.SourceFileLocation;
                else
                    sourceFileLocation = string.Concat(_FileConnectorConfiguration.SourceFileLocation, '\\');
                for (int i = 0; i < _FileConnectorConfiguration.SourceFileFilters.Count; i++)
                {
                    _LastDummyRunIndex += 1;
                    if (_LastDummyRunIndex >= _FileConnectorConfiguration.SourceFileFilters.Count)
                        _LastDummyRunIndex = 0;
                    sourceFileFilter = _FileConnectorConfiguration.SourceFileFilters[_LastDummyRunIndex];
                    sourceArchiveFile = Path.GetFullPath(string.Concat(sourceFileLocation, sourceFileFilter));
                    if (File.Exists(sourceArchiveFile))
                    {
                        checkSegment = _FileConnectorConfiguration.TargetFileLocation.Substring(sourceFileLocation.Length);
                        checkDirectory = Path.GetDirectoryName(sourceArchiveFile);
                        for (int z = 0; z < int.MaxValue; z++)
                        {
                            if (checkDirectory.Length < sourceFileLocation.Length || !checkDirectory.StartsWith(sourceFileLocation))
                                break;
                            checkDirectory = Path.GetDirectoryName(checkDirectory);
                            if (Directory.Exists(Path.Combine(checkDirectory, checkSegment)))
                            {
                                checkDirectory = Path.Combine(checkDirectory, checkSegment);
                                break;
                            }
                        }
                        if (!checkDirectory.EndsWith(checkSegment))
                            throw new Exception("Could not determine dummy target directory for extract!");
                        if (!long.TryParse(Path.GetFileNameWithoutExtension(sourceArchiveFile).Replace("x", string.Empty), out long sequence))
                            throw new Exception("Invalid file name for source archive file!");
                        pathSegment = checkDirectory.Substring(sourceFileLocation.Length);
                        monARessource = GetCellName(pathSegment);
                        if (string.IsNullOrEmpty(monARessource))
                            throw new Exception("Could not determine which cell archive file is associated with!");
                        if (_IsEAFHosted)
                            CallbackFileExists(sourceArchiveFile, traceDummyFile, checkDirectory, monARessource, sequence);
                        break;
                    }
                }
            }
        }
        catch (Exception exception)
        {
            string subject = string.Concat("Exception:", _CellInstanceConnectionName);
            string body = string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace);
            try
            { _SMTP.SendHighPriorityEmailMessage(subject, body); }
            catch (Exception) { }
        }
        try
        {
            TimeSpan timeSpan = new(DateTime.Now.AddSeconds(_FileConnectorConfiguration.FileScanningIntervalInSeconds.Value).Ticks - DateTime.Now.Ticks);
            _ = _Timer.Change((long)timeSpan.TotalMilliseconds, Timeout.Infinite);
        }
        catch (Exception exception)
        {
            string subject = string.Concat("Exception:", _CellInstanceConnectionName);
            string body = string.Concat(exception.Message, Environment.NewLine, Environment.NewLine, exception.StackTrace);
            try
            { _SMTP.SendHighPriorityEmailMessage(subject, body); }
            catch (Exception) { }
        }
    }

}