using System.Text.Json;
using System.Text.Json.Serialization;

namespace View_by_Distance.Property.Models;

public class Configuration : Shared.Models.Properties.IPropertyConfiguration
{

    protected string? _ModelName;
    protected int? _NumberOfJitters;
    protected int? _NumberOfTimesToUpsample;
    protected string? _PredictorModelName;
    protected string _RootDirectory;
    public string? ModelName => _ModelName;
    public int? NumberOfJitters => _NumberOfJitters;
    public int? NumberOfTimesToUpsample => _NumberOfTimesToUpsample;
    public string? PredictorModelName => _PredictorModelName;
    public string RootDirectory => _RootDirectory;

    public string DateGroup { init; get; }
    public string FileNameDirectorySeparator { init; get; }
    public bool ForcePropertyLastWriteTimeToCreationTime { init; get; }
    public string[] IgnoreExtensions { init; get; }
    public int MaxImagesInDirectoryForTopLevelFirstPass { init; get; }
    public string Pattern { init; get; }
    public bool PopulatePropertyId { init; get; }
    public bool PropertiesChangedForProperty { init; get; }
    public string[] PropertyContentCollectionFiles { init; get; }
    public string ResultAllInOne { init; get; }
    public string ResultCollection { init; get; }
    public string ResultContent { init; get; }
    public string ResultSingleton { init; get; }
    public string[] ValidImageFormatExtensions { init; get; }
    public string[] ValidMetadataExtensions { init; get; }
    public string[] VerifyToSeason { init; get; }
    public bool WriteBitmapDataBytes { init; get; }

    [JsonConstructor]
    public Configuration(string dateGroup,
                         string fileNameDirectorySeparator,
                         bool forcePropertyLastWriteTimeToCreationTime,
                         string[] ignoreExtensions,
                         int maxImagesInDirectoryForTopLevelFirstPass,
                         string pattern,
                         bool populatePropertyId,
                         bool propertiesChangedForProperty,
                         string[] propertyContentCollectionFiles,
                         string resultAllInOne,
                         string resultCollection,
                         string resultContent,
                         string resultSingleton,
                         string rootDirectory,
                         string[] validImageFormatExtensions,
                         string[] validMetadataExtensions,
                         string[] verifyToSeason,
                         bool writeBitmapDataBytes)
    {
        DateGroup = dateGroup;
        FileNameDirectorySeparator = fileNameDirectorySeparator;
        ForcePropertyLastWriteTimeToCreationTime = forcePropertyLastWriteTimeToCreationTime;
        IgnoreExtensions = ignoreExtensions;
        MaxImagesInDirectoryForTopLevelFirstPass = maxImagesInDirectoryForTopLevelFirstPass;
        Pattern = pattern;
        PopulatePropertyId = populatePropertyId;
        PropertiesChangedForProperty = propertiesChangedForProperty;
        PropertyContentCollectionFiles = propertyContentCollectionFiles;
        ResultAllInOne = resultAllInOne;
        ResultCollection = resultCollection;
        ResultContent = resultContent;
        ResultSingleton = resultSingleton;
        _RootDirectory = rootDirectory;
        ValidImageFormatExtensions = validImageFormatExtensions;
        ValidMetadataExtensions = validMetadataExtensions;
        VerifyToSeason = verifyToSeason;
        WriteBitmapDataBytes = writeBitmapDataBytes;
    }

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

    public void ChangeRootDirectory(string rootDirectory) => _RootDirectory = rootDirectory;

    public void Update(int? numberOfJitters, int? numberOfTimesToUpsample, string? modelName, string? predictorModelName)
    {
        _NumberOfJitters = numberOfJitters;
        _NumberOfTimesToUpsample = numberOfTimesToUpsample;
        _ModelName = modelName;
        _PredictorModelName = predictorModelName;
        _RootDirectory = Path.GetFullPath(_RootDirectory);
    }

    public static void Verify(Configuration propertyConfiguration, bool requireExist)
    {
        if (propertyConfiguration is null)
            throw new NullReferenceException(nameof(propertyConfiguration));
        if (propertyConfiguration.IgnoreExtensions is null || !propertyConfiguration.IgnoreExtensions.Any())
            throw new NullReferenceException(nameof(propertyConfiguration.IgnoreExtensions));
        if (propertyConfiguration.PropertyContentCollectionFiles is null)
            throw new NullReferenceException(nameof(propertyConfiguration.PropertyContentCollectionFiles));
        if (propertyConfiguration.ValidImageFormatExtensions is null || !propertyConfiguration.ValidImageFormatExtensions.Any())
            throw new NullReferenceException(nameof(propertyConfiguration.ValidImageFormatExtensions));
        if (propertyConfiguration.ValidMetadataExtensions is null || !propertyConfiguration.ValidMetadataExtensions.Any())
            throw new NullReferenceException(nameof(propertyConfiguration.ValidMetadataExtensions));
        if (propertyConfiguration.VerifyToSeason is null || !propertyConfiguration.VerifyToSeason.Any())
            throw new NullReferenceException(nameof(propertyConfiguration.VerifyToSeason));
        if (Path.GetPathRoot(propertyConfiguration.RootDirectory) == propertyConfiguration.RootDirectory)
            throw new NullReferenceException(nameof(propertyConfiguration.RootDirectory));
        if (propertyConfiguration is null)
            throw new NullReferenceException(nameof(propertyConfiguration));
        if (string.IsNullOrEmpty(propertyConfiguration.DateGroup))
            throw new NullReferenceException(nameof(propertyConfiguration.DateGroup));
        if (string.IsNullOrEmpty(propertyConfiguration.FileNameDirectorySeparator))
            throw new NullReferenceException(nameof(propertyConfiguration.FileNameDirectorySeparator));
        if (string.IsNullOrEmpty(propertyConfiguration.Pattern))
            throw new NullReferenceException(nameof(propertyConfiguration.Pattern));
        if (string.IsNullOrEmpty(propertyConfiguration.RootDirectory) || (requireExist && !Directory.Exists(propertyConfiguration.RootDirectory)))
            throw new NullReferenceException(nameof(propertyConfiguration.RootDirectory));
    }

}