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

namespace View_by_Distance.Shared.Models;

public class Location : Properties.ILocation, IEquatable<Location>
{

    public int Bottom { init; get; }
    public double Confidence { init; get; }
    public int Left { init; get; }
    public int Right { init; get; }
    public int Top { init; get; }

    [JsonConstructor]
    public Location(int bottom, double confidence, int left, int right, int top)
    {
        Confidence = confidence;
        Bottom = bottom;
        Left = left;
        Right = right;
        Top = top;
        _ = Stateless.Methods.Location.Check(bottom, left, right, top, zCount: 1, throwException: true);
    }

    public Location(double confidence, int height, Location location, int locationDigits, int locationFactor, int width, int zCount) :
        this(
            location.Bottom,
            confidence,
            location.Left,
            location.Right,
            location.Top) =>
        Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount, throwException: true);

    public Location(int bottom, double confidence, int height, int left, int locationDigits, int locationFactor, int right, int top, int width, int zCount) :
        this(
            bottom,
            confidence,
            left,
            right,
            top) =>
        Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount, throwException: true);

    public Location(int height, Location location, int locationDigits, int locationFactor, int width, int zCount) :
        this(
            location.Bottom,
            location.Confidence,
            location.Left,
            location.Right,
            location.Top) =>
        Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount, throwException: true);

    public Location(double confidence, int factor, int height, Location location, int locationDigits, int locationFactor, int width, int zCount)
    {
        int x = (location.Right - location.Left) / factor;
        int y = (location.Bottom - location.Top) / factor;
        int bottom = Math.Min(location.Bottom + y, height);
        int left = Math.Max(location.Left - x, 0);
        int right = Math.Min(location.Right + x, width);
        int top = Math.Max(location.Top - y, 0);
        _ = Stateless.Methods.Location.Check(Bottom, height, Left, Right, Top, width, zCount, throwException: true);
        Confidence = confidence;
        Bottom = bottom;
        Left = left;
        Right = right;
        Top = top;
    }

    public override bool Equals(object? obj) => Equals(obj as Location);

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

#pragma warning disable IDE0070
    public override int GetHashCode()
#pragma warning restore IDE0070
    {
        int hashCode = -773114317;
        hashCode = hashCode * -1521134295 + Bottom.GetHashCode();
        hashCode = hashCode * -1521134295 + Left.GetHashCode();
        hashCode = hashCode * -1521134295 + Right.GetHashCode();
        hashCode = hashCode * -1521134295 + Top.GetHashCode();
        return hashCode;
    }

    public bool Equals(Location? location)
    {
        return location is not null
            && Bottom == location.Bottom
            && Left == location.Left
            && Right == location.Right
            && Top == location.Top;
    }

    public static bool operator ==(Location location1, Location location2) => EqualityComparer<Location>.Default.Equals(location1, location2);

    public static bool operator !=(Location location1, Location location2) => !(location1 == location2);

}