using Humanizer;
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Phares.Shared;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Stateless.Methods;
using View_by_Distance.Tests.Models;

namespace View_by_Distance.Tests;

[TestClass]
public partial class UnitTestCalculations
{

    private readonly AppSettings _AppSettings;
    private readonly string _WorkingDirectory;
    private readonly Configuration _Configuration;
    private readonly IsEnvironment _IsEnvironment;
    private readonly IConfigurationRoot _ConfigurationRoot;
    private readonly Property.Models.Configuration _PropertyConfiguration;

    public UnitTestCalculations()
    {
        AppSettings appSettings;
        string workingDirectory;
        Configuration configuration;
        IsEnvironment isEnvironment;
        IConfigurationRoot configurationRoot;
        Property.Models.Configuration propertyConfiguration;
        Assembly assembly = Assembly.GetExecutingAssembly();
        bool debuggerWasAttachedAtLineZero = Debugger.IsAttached || assembly.Location.Contains(@"\bin\Debug");
        isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero);
        IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
            .AddEnvironmentVariables()
            .AddUserSecrets<UnitTestCalculations>();
        configurationRoot = configurationBuilder.Build();
        appSettings = Models.Binder.AppSettings.Get(configurationRoot);
        if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName))
            throw new Exception("Working directory name must have a value!");
        workingDirectory = IWorkingDirectory.GetWorkingDirectory(assembly.GetName().Name, appSettings.WorkingDirectoryName);
        Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory);
        propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot);
        configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration);
        _AppSettings = appSettings;
        _Configuration = configuration;
        _IsEnvironment = isEnvironment;
        _WorkingDirectory = workingDirectory;
        _ConfigurationRoot = configurationRoot;
        _PropertyConfiguration = propertyConfiguration;
    }

    private static void NonThrowTryCatch()
    {
        try
        { throw new Exception(); }
        catch (Exception) { }
    }

    [TestMethod]
    public void TestMethodNull()
    {
        Assert.IsFalse(_AppSettings is null);
        Assert.IsFalse(_Configuration is null);
        Assert.IsFalse(_IsEnvironment is null);
        Assert.IsFalse(_WorkingDirectory is null);
        Assert.IsFalse(_ConfigurationRoot is null);
        Assert.IsFalse(_PropertyConfiguration is null);
        NonThrowTryCatch();
    }

    [TestMethod]
    public void TestMethodGetSort() => Assert.IsTrue(new bool[] { true, false }.OrderByDescending(l => l).First());

    [TestMethod]
    public void TestMethodGetAge()
    {
        PersonBirthday personBirthday = new(new(1980, 1, 17));
        double? age = IPersonBirthday.GetAge(personBirthday);
        if (age is null)
            throw new NullReferenceException(nameof(age));
        Assert.IsNotNull(age);
        Assert.IsTrue(age.Value > 42.6092);
        NonThrowTryCatch();
    }

    [TestMethod]
    public void TestMethodParse()
    {
        Assert.IsTrue(long.TryParse("(637967784888423594)"[1..^1], out long ticks));
        Assert.IsTrue(ticks == 637967784888423594);
        Assert.IsFalse(long.TryParse("(637967784888423594.61)"[1..^1], out ticks));
        Assert.IsTrue(ticks == 0);
        Assert.IsFalse(long.TryParse("(637967784888423594.00)"[1..^1], out ticks));
        Assert.IsTrue(ticks == 0);
        long l = 637967784888423594;
        double d;
        d = 0.61;
        Assert.IsTrue($"({l}{d.ToString("0.00")[1..]})" == "(637967784888423594.61)");
        d = 0.6;
        Assert.IsTrue($"({l}{d.ToString("0.00")[1..]})" == "(637967784888423594.60)");
        d = 0.615;
        Assert.IsTrue($"({l}{d.ToString("0.00")[1..]})" == "(637967784888423594.62)");
        d = 0.45;
        Assert.IsTrue($"({l}{d.ToString("0.00")[1..]})" == "(637967784888423594.45)");
        NonThrowTryCatch();
    }

    [TestMethod]
    public void TestMethodHumanize()
    {
        string successful = $"_ {nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title)} Successful";
        Assert.IsTrue(successful == "_ Manual Copy Successful");
        string verify = $"_ {nameof(Shared.Models.Stateless.IMapLogic.ManualCopy).Humanize(LetterCasing.Title)} Verify";
        Assert.IsTrue(verify == "_ Manual Copy Verify");
        NonThrowTryCatch();
    }

    [TestMethod]
    public void TestMethodDirectory()
    {
        string[] names;
        names = IPath.GetDirectoryNames(@"C:\Tmp\phares");
        Assert.IsTrue(names.Length == 3);
        names = IPath.GetDirectoryNames(@"C:\Tmp\phares\");
        Assert.IsTrue(names.Length == 3);
        // names = IPath.GetDirectoryNames(@"C:\Tmp\phares\Pictures - Results\E) Distance\2022-09-15\7680 x 4320\7680x4320 - Hog - Large\()\(637991752537712052)\1976-03-08_00\#2019\K\-735727008.520765.jpg");
        // Assert.IsTrue(names.Length == 13);
        // Length = 13
        // [0] [string]:
        // "C:\\"
        // [1] [string]:
        // "Tmp"
        // [2] [string]:
        // "phares"
        // [3] [string]:
        // "Pictures - Results"
        // [4] [string]:
        // "E) Distance"
        // [5] [string]:
        // "2022-09-15"
        // [6] [string]:
        // "7680 x 4320"
        // [7] [string]:
        // "7680x4320 - Hog - Large"
        // [8] [string]:
        // "()"
        NonThrowTryCatch();
    }

    [TestMethod]
    public void TestGetLocation()
    {
        double confidence = 0.1D;
        int left, top, right, bottom, width, height;
        left = 20;
        right = 60;
        top = 40;
        bottom = 80;
        width = 100;
        height = 100;
        Location location = new(bottom, confidence, left, right, top);
        _ = new Location(confidence, height, location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, width, 1);
        _ = new Location(bottom, confidence, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width, 1);
        NonThrowTryCatch();
    }

    [TestMethod]
    public void TestAreaPermyriad()
    {
        int faceAreaPermyriad = 10000;
        Location location;
        double confidence = 0.1D;
        int areaPermyriad, left, top, right, bottom, width, height;
        left = 0;
        right = 100;
        top = 0;
        bottom = 100;
        width = 100;
        height = 100;
        areaPermyriad = IMapping.GetAreaPermyriad(faceAreaPermyriad, bottom, height, left, right, top, width);
        Assert.IsTrue(areaPermyriad == 10000);
        left = 0;
        right = 50;
        top = 0;
        bottom = 50;
        width = 100;
        height = 100;
        location = new(bottom, confidence, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width, 1);
        areaPermyriad = IMapping.GetAreaPermyriad(faceAreaPermyriad, height, location, width);
        Assert.IsTrue(areaPermyriad == 2500);
        left = 0;
        right = 25;
        top = 0;
        bottom = 25;
        width = 100;
        height = 100;
        location = new(bottom, confidence, height, left, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, right, top, width, 1);
        OutputResolution outputResolution = new(height, 0, width);
        areaPermyriad = IMapping.GetAreaPermyriad(faceAreaPermyriad, location, outputResolution);
        Assert.IsTrue(areaPermyriad == 625);
        NonThrowTryCatch();
    }

    [TestMethod]
    public void TestGetDistance()
    {
        double x1, x2, y1, y2;
        x1 = 12f;
        x2 = 13f;
        y1 = 11f;
        y2 = 10f;
        double distance = Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2));
        Assert.IsTrue(distance == 1.4142135623730951);
        NonThrowTryCatch();
    }

    [TestMethod]
    public void TestGetConfidencePercent()
    {
        int faceConfidencePercent = 100;
        float value, check;
        value = 0f;
        check = ILocation.GetConfidencePercent(faceConfidencePercent, value);
        Assert.IsTrue(check == 0);
        value = 0.4f;
        check = ILocation.GetConfidencePercent(faceConfidencePercent, value);
        Assert.IsTrue(check == 40);
        value = 0.8f;
        check = ILocation.GetConfidencePercent(faceConfidencePercent, value);
        Assert.IsTrue(check == 80);
        value = 1.6f;
        check = ILocation.GetConfidencePercent(faceConfidencePercent, value);
        Assert.IsTrue(check == 160);
        NonThrowTryCatch();
    }

    [TestMethod]
    public void TestMethodMonth()
    {
        Assert.AreEqual(IPersonBirthday.GetDate("jan", "17", "1980"), new DateTime(1980, 1, 17));
        Assert.AreEqual(IPersonBirthday.GetDate("january", "17", "1980"), new DateTime(1980, 1, 17));
        Assert.AreEqual(IPersonBirthday.GetDate("f", "17", "1980"), new DateTime(1980, 2, 17));
        Assert.AreEqual(IPersonBirthday.GetDate("01", "17", "1980"), new DateTime(1980, 1, 17));
        Assert.AreEqual(IPersonBirthday.GetDate("1", "17", "1980"), new DateTime(1980, 1, 17));
        Assert.IsNull(IPersonBirthday.GetDate("pan", "17", "1980"));
        Assert.IsNull(IPersonBirthday.GetDate("j-a-n-u-a-r-y", "17", "1980"));
        Assert.IsNull(IPersonBirthday.GetDate("j", "17", "1980"));
        Assert.IsNull(IPersonBirthday.GetDate("13", "17", "1980"));
        Assert.IsNull(IPersonBirthday.GetDate("0", "17", "1980"));
        NonThrowTryCatch();
    }

    [TestMethod]
    public void TestMethodIntersect()
    {
        float? percent;
        float? areaA = null;
        RectangleF rectangleA;
        RectangleF rectangleB;
        rectangleA = new(0, 0, 4, 4);
        rectangleB = new(0, 0, 4, 4);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == 1);
        rectangleA = new(0, 0, 4, 4);
        rectangleB = new(0, 0, 2, 2);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == .25);
        rectangleA = new(0, 0, 4, 4);
        rectangleB = new(0, 0, 4, 2);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == .5);
        rectangleA = new(0, 0, 4, 4);
        rectangleB = new(2, 2, 4, 4);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == .25);
        rectangleA = new(0, 0, 4, 4);
        rectangleB = new(2, 0, 4, 4);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == .5);
        rectangleA = new(0, 0, 4, 4);
        rectangleB = new(2, 4, 4, 4);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == 0);
        rectangleB = new(0, 0, 4, 4);
        rectangleA = new(0, 0, 4, 4);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == 1);
        rectangleB = new(0, 0, 4, 4);
        rectangleA = new(0, 0, 2, 2);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == .25);
        rectangleB = new(0, 0, 4, 4);
        rectangleA = new(0, 0, 4, 2);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == .5);
        rectangleB = new(0, 0, 4, 4);
        rectangleA = new(2, 2, 4, 4);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == .25);
        rectangleB = new(0, 0, 4, 4);
        rectangleA = new(2, 0, 4, 4);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == .5);
        rectangleB = new(0, 0, 4, 4);
        rectangleA = new(2, 4, 4, 4);
        percent = ILocation.GetIntersectPercent(rectangleA, areaA, rectangleB);
        Assert.IsNotNull(percent);
        Assert.IsTrue(percent.Value == 0);
        NonThrowTryCatch();
    }

}