using System.Text.Json;
using View_by_Distance.Metadata.Models;
using View_by_Distance.Resize.Models;
using View_by_Distance.Shared.Models.Stateless;

namespace View_by_Distance.Instance.Models;

/// <summary>
// N/A
/// </summary>
internal class E3_Rename
{

    private readonly Serilog.ILogger? _Log;
    private readonly Configuration _Configuration;
    private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions;

    internal E3_Rename(Configuration configuration)
    {
        _Configuration = configuration;
        _Log = Serilog.Log.ForContext<G2_Identify>();
        _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
    }

    public override string ToString()
    {
        string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
        return result;
    }

    internal string[] GetDirectoryRenameCollection(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string relativePath, string newDirectoryName, bool jsonFiles4InfoAny)
    {
        List<string> results = new();
        bool add;
        string to;
        string dFacesContentDirectory;
        string cResizeContentDirectory;
        string dFacesCollectionDirectory;
        string cResizeSingletonDirectory;
        string eDistanceContentDirectory;
        string aPropertySingletonDirectory;
        string d2FacePartsContentDirectory;
        string bMetadataSingletonDirectory;
        string eDistanceCollectionDirectory;
        string g2IdentifyCollectionDirectory;
        add = Directory.Exists(string.Concat(Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(C_Resize), _Configuration.ValidResolutions[0], includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()"), relativePath));
        bMetadataSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(B_Metadata), "{}");
        if (Directory.Exists(bMetadataSingletonDirectory))
        {
            to = Path.Combine(string.Concat(bMetadataSingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
            results.Add(to);
        }
        aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(Property.Models.A_Property), "{}");
        if (Directory.Exists(aPropertySingletonDirectory))
        {
            to = Path.Combine(string.Concat(aPropertySingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
            results.Add(to);
        }
        cResizeContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(C_Resize), _Configuration.ValidResolutions[0], includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()");
        if (Directory.Exists(cResizeContentDirectory))
        {
            to = Path.Combine(string.Concat(cResizeContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
            results.Add(to);
        }
        foreach (string outputResolution in _Configuration.ValidResolutions)
        {
            cResizeSingletonDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "{}");
            if (Directory.Exists(cResizeSingletonDirectory))
            {
                to = Path.Combine(string.Concat(cResizeSingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(to);
            }
            dFacesContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()");
            if (Directory.Exists(dFacesContentDirectory))
            {
                to = Path.Combine(string.Concat(dFacesContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(to);
            }
            dFacesCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]");
            if (Directory.Exists(dFacesCollectionDirectory))
            {
                to = Path.Combine(string.Concat(dFacesCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(to);
            }
            d2FacePartsContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D2_FaceParts), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()");
            if (add && _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution) && Directory.Exists(d2FacePartsContentDirectory))
            {
                to = Path.Combine(string.Concat(d2FacePartsContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(to);
            }
            eDistanceContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()");
            if (Directory.Exists(eDistanceContentDirectory))
            {
                to = Path.Combine(string.Concat(eDistanceContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(to);
            }
            eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]");
            if (Directory.Exists(eDistanceCollectionDirectory))
            {
                to = Path.Combine(string.Concat(eDistanceCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(to);
            }
            g2IdentifyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(G2_Identify), "[]");
            if (add && jsonFiles4InfoAny && Directory.Exists(g2IdentifyCollectionDirectory))
            {
                to = Path.Combine(string.Concat(g2IdentifyCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(to);
            }
        }
        return results.ToArray();
    }

    internal List<string[]> GetDirectoryRenameCollections(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string relativePath, string newDirectoryName, bool jsonFiles4InfoAny)
    {
        List<string[]> results = new();
        bool add;
        string to;
        bool exists;
        string from;
        string dFacesContentDirectory;
        string cResizeContentDirectory;
        string dFacesCollectionDirectory;
        string cResizeSingletonDirectory;
        string eDistanceContentDirectory;
        string bMetadataSingletonDirectory;
        string aPropertySingletonDirectory;
        string d2FacePartsContentDirectory;
        string eDistanceCollectionDirectory;
        string g2IdentifyCollectionDirectory;
        if (!string.IsNullOrEmpty(relativePath))
        {
            from = string.Concat(_Configuration.PropertyConfiguration.RootDirectory, relativePath);
            to = Path.Combine(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
            results.Add(new string[] { from, to });
        }
        foreach (string outputResolution in _Configuration.ValidResolutions)
        {
            add = Directory.Exists(string.Concat(Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()"), relativePath));
            bMetadataSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(B_Metadata), "{}");
            from = string.Concat(bMetadataSingletonDirectory, relativePath);
            exists = Directory.Exists(bMetadataSingletonDirectory);
            if (exists)
            {
                to = Path.Combine(string.Concat(bMetadataSingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(new string[] { from, to });
            }
            aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(Property.Models.A_Property), "{}");
            from = string.Concat(aPropertySingletonDirectory, relativePath);
            exists = Directory.Exists(aPropertySingletonDirectory);
            if (exists)
            {
                to = Path.Combine(string.Concat(aPropertySingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(new string[] { from, to });
            }
            cResizeContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()");
            from = string.Concat(cResizeContentDirectory, relativePath);
            exists = Directory.Exists(cResizeContentDirectory);
            if (exists)
            {
                to = Path.Combine(string.Concat(cResizeContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(new string[] { from, to });
            }
            cResizeSingletonDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false), "{}");
            from = string.Concat(cResizeSingletonDirectory, relativePath);
            exists = Directory.Exists(cResizeSingletonDirectory);
            if (exists)
            {
                to = Path.Combine(string.Concat(cResizeSingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(new string[] { from, to });
            }
            dFacesContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()");
            from = string.Concat(dFacesContentDirectory, relativePath);
            exists = Directory.Exists(dFacesContentDirectory);
            if (exists)
            {
                to = Path.Combine(string.Concat(dFacesContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(new string[] { from, to });
            }
            dFacesCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]");
            from = string.Concat(dFacesCollectionDirectory, relativePath);
            exists = Directory.Exists(dFacesCollectionDirectory);
            if (exists)
            {
                to = Path.Combine(string.Concat(dFacesCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(new string[] { from, to });
            }
            d2FacePartsContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D2_FaceParts), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()");
            from = string.Concat(d2FacePartsContentDirectory, relativePath);
            exists = Directory.Exists(d2FacePartsContentDirectory);
            if (!exists && add && _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution))
                results.Add(new string[] { from });
            else if (exists)
            {
                to = Path.Combine(string.Concat(d2FacePartsContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(new string[] { from, to });
            }
            eDistanceContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()");
            from = string.Concat(eDistanceContentDirectory, relativePath);
            exists = Directory.Exists(eDistanceContentDirectory);
            if (exists)
            {
                to = Path.Combine(string.Concat(eDistanceContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(new string[] { from, to });
            }
            eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]");
            from = string.Concat(eDistanceCollectionDirectory, relativePath);
            exists = Directory.Exists(eDistanceCollectionDirectory);
            if (exists)
            {
                to = Path.Combine(string.Concat(eDistanceCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(new string[] { from, to });
            }
            g2IdentifyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(G2_Identify), "[]");
            from = string.Concat(g2IdentifyCollectionDirectory, relativePath);
            exists = Directory.Exists(g2IdentifyCollectionDirectory);
            if (!exists && add && jsonFiles4InfoAny)
                results.Add(new string[] { from });
            else if (exists)
            {
                to = Path.Combine(string.Concat(g2IdentifyCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName);
                results.Add(new string[] { from, to });
            }
        }
        return results;
    }

    internal void DirectoryRename(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string relativePath, string newDirectoryName)
    {
        string json;
        FileInfo current;
        FileInfo fileInfo;
        string error = "Error";
        string target = "Target";
        string pending = "Pending";
        DirectoryInfo directoryInfo;
        IEnumerator<FileInfo> fileInfoCollection;
        string oldValue = string.Concat("\"", relativePath);
        string oldDirectoryName = Path.GetFileName(relativePath);
        string traceFileName = string.Concat(DateTime.Now.Ticks, ".tsv");
        string directoryName = Path.GetFileName(_Configuration.PropertyConfiguration.RootDirectory);
        string? relativePathParent = Path.GetDirectoryName(relativePath);
        if (string.IsNullOrEmpty(relativePathParent))
            throw new Exception();
        string newValue = string.Concat("\"", Path.Combine(relativePathParent, newDirectoryName));
        string e3RenameContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(E3_Rename), "()");
        string jsonRootDirectory = Path.Combine(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, " - Copied"), string.Concat(directoryName, " - 4) Info"), _Configuration.PropertyConfiguration.DateGroup, "[]");
        directoryInfo = new DirectoryInfo(jsonRootDirectory);
        if (!directoryInfo.Exists)
            directoryInfo.Create();
        IEnumerator<FileInfo> fileInfoCollection4 = directoryInfo.EnumerateFiles("*.json", SearchOption.AllDirectories).GetEnumerator();
        bool fileInfoCollection4MoveNext = fileInfoCollection4.MoveNext();
        if (!fileInfoCollection4MoveNext)
            current = new(string.Empty);
        else
            current = fileInfoCollection4.Current;
        List<string[]> directoryCollections = GetDirectoryRenameCollections(configuration, model, predictorModel, relativePath, newDirectoryName, fileInfoCollection4MoveNext);
        if ((from l in directoryCollections where l.Length != 2 select true).Any())
            throw new Exception();
        if (!Directory.Exists(e3RenameContentDirectory))
        {
            _ = Directory.CreateDirectory(e3RenameContentDirectory);
            _ = Directory.CreateDirectory(Path.Combine(e3RenameContentDirectory, error));
            _ = Directory.CreateDirectory(Path.Combine(e3RenameContentDirectory, target));
            _ = Directory.CreateDirectory(Path.Combine(e3RenameContentDirectory, "Test"));
            _ = Directory.CreateDirectory(Path.Combine(e3RenameContentDirectory, pending));
        }
        string fRandomSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(F_Random), "{}");
        string[] files = Directory.GetFiles(fRandomSingletonDirectory, "*", SearchOption.TopDirectoryOnly);
        foreach (string file in files)
            File.Delete(file);
        File.WriteAllText(Path.Combine(e3RenameContentDirectory, pending, traceFileName), string.Concat(relativePath, newDirectoryName, Environment.NewLine));
        try
        {
            foreach (string[] directoryCollection in directoryCollections)
            {
                directoryInfo = new DirectoryInfo(directoryCollection[0]);
                if (!directoryInfo.Exists)
                    continue;
                fileInfoCollection = directoryInfo.EnumerateFiles("*.json", SearchOption.AllDirectories).GetEnumerator();
                for (int i = 0; i < int.MaxValue; i++)
                {
                    if (fileInfoCollection.MoveNext())
                        fileInfo = fileInfoCollection.Current;
                    else if (fileInfoCollection4MoveNext && fileInfoCollection4.MoveNext())
                        fileInfo = fileInfoCollection4.Current;
                    else if (fileInfoCollection4MoveNext && current is not null)
                    {
                        fileInfo = current;
                        current = new(string.Empty);
                    }
                    else
                        break;
                    json = Shared.Models.Stateless.Methods.IIndex.GetJson(fileInfo.FullName, fileInfo);
                    if (json.Contains(oldValue))
                    {
                        json = json.Replace(oldValue, newValue);
                        if (!Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true))
                            continue;
                        File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime);
                    }
                }
                Directory.Move(directoryCollection[0], directoryCollection[1]);
            }
            File.Move(Path.Combine(e3RenameContentDirectory, pending, traceFileName), Path.Combine(e3RenameContentDirectory, target, traceFileName));
        }
        catch (Exception)
        {
            File.Move(Path.Combine(e3RenameContentDirectory, pending, traceFileName), Path.Combine(e3RenameContentDirectory, error, traceFileName));
            throw;
        }
    }

    internal void RenameQueue(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel)
    {
        string[] lines;
        string[] segments;
        string e3RenameContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(E3_Rename), "()");
        string[] files = Directory.GetFiles(e3RenameContentDirectory, "*.tsv", SearchOption.TopDirectoryOnly);
        foreach (string file in files)
        {
            lines = File.ReadAllLines(file);
            foreach (string line in lines)
            {
                if (string.IsNullOrEmpty(line) || !line.Contains('\t'))
                    continue;
                segments = line.Split('\t');
                if (segments.Length != 2)
                    throw new Exception();
                DirectoryRename(configuration, model, predictorModel, segments[0], segments[1]);
            }
        }
    }

}