using System.Text.Json;

namespace View_by_Distance.Shared.Models.Stateless.Methods;

internal abstract class Face
{

    internal static string GetJson(string jsonFileFullName)
    {
        string result;
        FileInfo fileInfo;
        string fileSegment = "FileSegment";
        result = File.ReadAllText(jsonFileFullName);
        if (result.Contains(fileSegment))
        {
            fileInfo = new FileInfo(jsonFileFullName);
            result = result.Replace(fileSegment, nameof(Properties.IIndex.RelativePaths)).Replace("\\\\", "/");
            File.WriteAllText(fileInfo.FullName, result);
            File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime);
        }
        if (result.Contains("/u0"))
        {
            fileInfo = new FileInfo(jsonFileFullName);
            result = result.Replace("/u0", "\\u0");
            File.WriteAllText(fileInfo.FullName, result);
            File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime);
        }
        return result;
    }

    private static JsonElement[] GetJsonElements(string jsonFileFullName)
    {
        string json = GetJson(jsonFileFullName);
        JsonElement[]? jsonElements = JsonSerializer.Deserialize<JsonElement[]>(json);
        if (jsonElements is null)
            throw new Exception();
        return jsonElements;
    }

    private static List<Models.Face> GetFaces(string jsonFileFullName, int? maximum)
    {
        List<Models.Face> results = new();
        Tuple<Models.Face, string>? tuple;
        JsonElement[] jsonElements = GetJsonElements(jsonFileFullName);
        foreach (JsonElement jsonElement in jsonElements)
        {
            tuple = JsonSerializer.Deserialize<Tuple<Models.Face, string>>(jsonElement.ToString());
            if (tuple is null || tuple.Item1 is null || string.IsNullOrEmpty("tuple.Item1.RelativePath"))
                continue;
            results.Add(tuple.Item1);
            if (maximum.HasValue && results.Count >= maximum)
                break;
        }
        return results;
    }

    internal static Models.Face GetFace(string jsonFileFullName)
    {
        Models.Face? result;
        List<Models.Face> results = GetFaces(jsonFileFullName, maximum: 1);
        if (!results.Any())
            throw new Exception();
        result = results[0];
        return result;
    }

    internal static Models.Face[] GetFaces(string jsonFileFullName)
    {
        List<Models.Face> results = GetFaces(jsonFileFullName, maximum: null);
        return results.ToArray();
    }

    internal static double Getα(int x1, int x2, int y1, int y2)
    {
        double result;
        if (y1 == y2)
            result = 0;
        else
        {
            int b;
            if (x1 > x2)
                b = x1 - x2;
            else
                b = x2 - x1;
            int a;
            if (y1 > y2)
                a = y1 - y2;
            else
                a = y2 - y1;
            double c = Math.Sqrt(Math.Pow(a, 2) + Math.Pow(b, 2));
            if (y1 < y2)
                result = 180 / Math.PI * Math.Asin(a / c);
            else
                result = 180 / Math.PI * Math.Asin(a / c) * -1;
        }
        return result;
    }

    internal static double? Getα(Dictionary<FacePart, Models.FacePoint[]> faceParts)
    {
        double? result;
        int? leftEyeX = null;
        int? leftEyeY = null;
        int? rightEyeX = null;
        int? rightEyeY = null;
        foreach ((FacePart facePart, Models.FacePoint[] facePoints) in faceParts)
        {
            if (facePart is not FacePart.LeftEye and not FacePart.RightEye)
                continue;
            if (facePart is FacePart.LeftEye)
            {
                leftEyeX = (int)(from l in facePoints select l.X).Average();
                leftEyeY = (int)(from l in facePoints select l.Y).Average();
            }
            if (facePart is FacePart.RightEye)
            {
                rightEyeX = (int)(from l in facePoints select l.X).Average();
                rightEyeY = (int)(from l in facePoints select l.Y).Average();
            }
        }
        if (rightEyeX is null || leftEyeX is null || rightEyeY is null || leftEyeY is null)
            result = null;
        else
            result = Getα(rightEyeX.Value, leftEyeX.Value, rightEyeY.Value, leftEyeY.Value);
        return result;
    }

}