using System;

namespace StructureHelperCommon.Models.Shapes
{
    public class PolygonCalculator : IPolygonCalculator
    {
        public double GetPerimeter(ILinePolygonShape polygon)
        {
            if (polygon.Vertices.Count < 2)
                return 0;

            double perimeter = 0;

            for (int i = 0; i < polygon.Vertices.Count - 1; i++)
            {
                perimeter += Distance(polygon.Vertices[i].Point, polygon.Vertices[i + 1].Point);
            }

            if (polygon.IsClosed && polygon.Vertices.Count > 2)
            {
                perimeter += Distance(polygon.Vertices[^1].Point, polygon.Vertices[0].Point);
            }

            return perimeter;
        }

        public double GetArea(ILinePolygonShape polygon)
        {
            if (!polygon.IsClosed || polygon.Vertices.Count < 3)
                return 0;

            // Shoelace formula
            double sum = 0;
            for (int i = 0; i < polygon.Vertices.Count; i++)
            {
                var p1 = polygon.Vertices[i].Point;
                var p2 = polygon.Vertices[(i + 1) % polygon.Vertices.Count].Point;
                sum += (p1.X * p2.Y - p2.X * p1.Y);
            }

            return Math.Abs(sum) / 2.0;
        }

        public bool ContainsPoint(ILinePolygonShape polygon, IPoint2D point)
        {
            if (!polygon.IsClosed || polygon.Vertices.Count < 3)
                return false;

            // Ray casting algorithm
            bool inside = false;
            int j = polygon.Vertices.Count - 1;

            for (int i = 0; i < polygon.Vertices.Count; i++)
            {
                var pi = polygon.Vertices[i].Point;
                var pj = polygon.Vertices[j].Point;

                if (((pi.Y > point.Y) != (pj.Y > point.Y)) &&
                    (point.X < (pj.X - pi.X) * (point.Y - pi.Y) / (pj.Y - pi.Y) + pi.X))
                {
                    inside = !inside;
                }
                j = i;
            }

            return inside;
        }

        private double Distance(IPoint2D p1, IPoint2D p2)
        {
            double dx = p2.X - p1.X;
            double dy = p2.Y - p1.Y;
            return Math.Sqrt(dx * dx + dy * dy);
        }
    }

}
