using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using EmreIstikam001.component.TehranOffice.Components.ÇİZİM_YARDIMCILARI.Tab4_.DetailSymbol;
using EmreIstikam001.component.TehranOffice.ToosForAll;
using EmreIstikam001.Properties;
using Grasshopper.Kernel;
using Rhino;
using Rhino.DocObjects;
using Rhino.Geometry;
using Rhino.Input.Custom;
using Bitmap = System.Drawing.Bitmap;
using EmreIstikam001.component.TehranOffice.ToosForAll.BakeAndAttribute;
using EmreIstikam001.component.TehranOffice.ToosForAll.GeomatryDisplay;
using EmreIstikam001.component.TehranOffice.ToosForAll.GeomatryTools;
using Rhino.Input;
using Rhino.UI;
using System.Runtime.Remoting;
using System.Security.Cryptography.X509Certificates;
using static System.Net.Mime.MediaTypeNames;
using static EmreIstikam001.component.TehranOffice.ToosForAll.BakeAndAttribute.EIAttributesTl;


//using static EmreIstikam001.component.TehranOffice.Components._3D_DEN_2D_YE.PaftalamDetayAlma22GH;

namespace EmreIstikam001.component.TehranOffice.Components._3D_DEN_2D_YE.PaftalamDetayAlma
{
    public class CallOutGH : BaseGhComponent
    {
        private bool showGeometry = true;
        private bool bake = false;
        private bool closeForm = false;
        private string BlockName;

        private Guid guid;

        private Guid selectedInstanceId;
        private double DrawScale = 1.00;
        private double TextScale = 1.00;
        private bool Bake = false;

        private string LabelText = "D-A1";
        private Detail2DFormManager formManager;
        private GeometryData geometryData;
        private Detay2DConduit conduit;

        private List<RhinoObject> AllObjects = new List<RhinoObject>();

        private List<Curve> rectangle = new List<Curve>();
        private Detay2DRhinoInteractionHandler rhinoInteractionHandler;
        private static readonly List<GeometryBase> previewGeometryListDashed = new List<GeometryBase>();
        private static readonly List<GeometryBase> previewGeometryListNormal = new List<GeometryBase>();
        EIGeometryDisplayTI geometryDisplay = new EIGeometryDisplayTI();
        EIGeometryDisplayTI geometryDisplay2 = new EIGeometryDisplayTI(previewGeometryListDashed, true);
        List<RhinoObject> filteredObject = new List<RhinoObject>();
        List<RhinoObject> WhithoutInsstances = new List<RhinoObject>();


        private List<GeometryBase> AllGeometries = new List<GeometryBase>();
        private List<ObjectAttributes> AllAttributes = new List<ObjectAttributes>();
        public CallOutGH()
            : base("2D Callouts", "P", "DETAY ALMA", "PARDUS", "3D'DEN 2D'YE")
        {
            formManager = new Detail2DFormManager();
            conduit = new Detay2DConduit();
            rhinoInteractionHandler = new Detay2DRhinoInteractionHandler(conduit);
            InitializeEventHandlers();
        }
        protected override string CodeName => "DETAY_ALMA";
        protected override GH_Exposure? ValidExposure => GH_Exposure.primary;
        protected override Bitmap Icon => Resources.DETAY_ALMA;
        public override void AddedToDocument(GH_Document document)
        {
            base.AddedToDocument(document);

            // Show the form
            formManager.ShowForm();

            // Subscribe to form events
            formManager.DrawScaleChanged += OnDrawScaleChanged;
            formManager.TextScaleChanged += OnTextScaleChanged;
            formManager.DetailIdChanged += OnDetailIdChanged;
            formManager.GetPointsClicked += OnGetPointsClicked;
            formManager.GetBlockClicked += OnGetBlockClicked;
            formManager.BakeClicked += OnBakeClicked;
            formManager.FormClosed += OnFormClosed;
            formManager.Closed += OnFormClosed;
        }

        public override void RemovedFromDocument(GH_Document document)
        {
            base.RemovedFromDocument(document);
            if (geometryDisplay != null && geometryDisplay != null)
            {
                geometryDisplay.DisableDisplay();
                geometryDisplay2.DisableDisplay();
            }

            // Dispose of the form and conduit
            formManager.Dispose();
            conduit.Disable();
        }

        private void InitializeEventHandlers()
        {
        }

        private void OnDrawScaleChanged(object sender, double newDrawScale)
        {
            DrawScale = newDrawScale;
            rhinoInteractionHandler.RecalculateGeometryData();
            ExpireSolution(true);
        }

        private void OnTextScaleChanged(object sender, double newTextScale)
        {
            TextScale = newTextScale;
            rhinoInteractionHandler.Scale = newTextScale;
            rhinoInteractionHandler.RecalculateGeometryData();
            ExpireSolution(true);
        }

        private void OnDetailIdChanged(object sender, string newAxId)
        {
            LabelText = $"D-{newAxId}";
            rhinoInteractionHandler.DetailId = $"D-{newAxId}";
            rhinoInteractionHandler.RecalculateGeometryData();
            BlockName = LabelText;
            ExpireSolution(true);
        }

        private void OnGetPointsClicked(object sender, EventArgs e)
        {
            if (geometryDisplay != null && geometryDisplay != null)
            {
                geometryDisplay.DisableDisplay();
                geometryDisplay2.DisableDisplay();
            }

            // Disable the conduit to stop the preview
            if (conduit != null) conduit.Disable();
            // Initiate point picking in Rhino
            rhinoInteractionHandler.GetPointsFromUser(conduit);
            // Expire the solution to trigger a redraw
            RhinoDoc.ActiveDoc.Views.Redraw();

            rectangle.Clear();
            var geometryData = rhinoInteractionHandler.GetGeometryData();
            rectangle = geometryData.DashedCurves;
            ExpireSolution(true);
        }

        private void OnGetBlockClicked(object sender, EventArgs e)
        {
            //filter object instanceObjects 3096U + curve 4U + Hatch 65536U
            int filterobject = 4096 + 4 + 65536;
            var SelectedObjects = EIGetRihnoTl.GetAllGeomatry("SelectObjects", filterobject, true, true, true, false, true);
            foreach (var objRef in SelectedObjects)
            {
                var geometry = objRef.Object();
                AllObjects.Add(geometry);
            }
            //var uuu = FilterObjects(ttt);
            //InputDataFromRhino.AddRange(uuu);
            ExpireSolution(true);
        }

        private void OnBakeClicked(object sender, EventArgs e)
        {
            Bake = true;
            conduit.Disable();
            geometryDisplay.DisableDisplay();
            geometryDisplay2.DisableDisplay();
            RhinoDoc.ActiveDoc.Views.Redraw();
        }

        private void OnFormClosed(object sender, EventArgs e)
        {
            if (geometryDisplay != null && geometryDisplay != null)
            {
                geometryDisplay.DisableDisplay();
                geometryDisplay2.DisableDisplay();
            }

            // Dispose of the form and conduit
            formManager.Dispose();
            conduit.Disable();

            RhinoDoc.ActiveDoc.Views.Redraw();
            // Expire the solution to update the displ
        }
        protected override void RegisterInputParams(GH_InputParamManager pManager)
        {
        }

        protected override void RegisterOutputParams(GH_OutputParamManager pManager)
        {
            pManager.AddGenericParameter("C", "c", "c", GH_ParamAccess.list);
            pManager.AddGenericParameter("C", "c", "c", GH_ParamAccess.list);
            pManager.AddGenericParameter("C", "c", "c", GH_ParamAccess.list);
        }

        protected override void AuthenticatedSolveInstance(IGH_DataAccess DA)
        {
            var doc = RhinoDoc.ActiveDoc;

            if (rectangle.Count > 0)
            {
                // Update the conduit geometry based on the interaction handler's data
                geometryData = rhinoInteractionHandler.GetGeometryData();
                conduit.UpdateGeometry(geometryData, rhinoInteractionHandler.IsCancelled);
                // Redraw the viewport to reflect the changes
                RhinoDoc.ActiveDoc.Views.Redraw();
                foreach (var obj in AllObjects)
                {
                    if (obj is InstanceObject)
                    {
                        var instance = (InstanceObject)obj;
                        InstanceToolsTI.ExpandInstanceObjects(instance, WhithoutInsstances);
                    }
                    else
                    {
                        WhithoutInsstances.Add(obj);
                    }
                }


                filteredObject.AddRange(FilterObjects(WhithoutInsstances));


                foreach (var obj in filteredObject)
                {
                    List<Curve> outerHatchCurve = new List<Curve>();
                    List<Curve> innerHatchCurve = new List<Curve>();
                    List<Curve> ClosedTrimed = new List<Curve>();

                    if (obj is CurveObject)
                    {
                        Curve curveGeometry = (Curve)obj.Geometry;
                        var innerCurve = ProjectCurvesToBrep(curveGeometry, rectangle[0]);
                        if (innerCurve.Count > 0)
                        {
                            foreach (var crv in innerCurve)
                            {
                                //RhinoDoc.ActiveDoc.Objects.Add(crv, obj.Attributes);
                                AllGeometries.Add(crv);
                                AllAttributes.Add(obj.Attributes);
                            }

                        }
                    }

                    List<Curve> trimmedOuterCurves = new List<Curve>();
                    List<Curve> trimmedInnerCurves = new List<Curve>();
                    if (obj is HatchObject)
                    {
                        Hatch hatchObject = (Hatch)obj.Geometry;
                        outerHatchCurve.AddRange(hatchObject.Get3dCurves(true));
                        innerHatchCurve.AddRange(hatchObject.Get3dCurves(false));
                        List<double> tA = new List<double>();
                        List<double> tB = new List<double>();
                        bool isHatchInside = EICurveTI.IsCurveInsideRegion(outerHatchCurve[0], rectangle[0]);
                        bool isHatchInterects = EICurveTI.CurveCurveIntersection(outerHatchCurve[0], rectangle[0] ,out tA,out tB).Count == 0 ;

                        if (isHatchInside && isHatchInterects)
                        {
                            AllGeometries.Add(hatchObject);
                            AllAttributes.Add(obj.Attributes);
                        }
                        else
                        {
                            bool trim =TrimHatch(hatchObject, rectangle[0],out trimmedOuterCurves,out trimmedInnerCurves);
                            if (trim)
                            {

                                ClosedTrimed.AddRange(trimmedOuterCurves);
                                ClosedTrimed.AddRange(trimmedInnerCurves);
                                var newHatch = Hatch.Create(ClosedTrimed, hatchObject.PatternIndex, hatchObject.PatternRotation, hatchObject.PatternScale, 0.001);
                                //RhinoDoc.ActiveDoc.Objects.Add(ddd[0], obj.Attributes);
                                foreach (var hatch in newHatch)
                                { 
                                    AllGeometries.Add(hatch);
                                    AllAttributes.Add(obj.Attributes);
                                }
                            }
                        }
                    }
                }
                BoundingBox allBoundingBox = BoundingBox.Empty;
                foreach (var crv in AllGeometries)
                {
                    if (crv is Curve)
                    {
                        var boundingBoxCurve = crv.GetBoundingBox(true);
                        allBoundingBox.Union(boundingBoxCurve);
                    }

                }

                double movedistance = allBoundingBox.GetEdges()[0].Length;
                Point3d resultPosition = new Point3d(
                    allBoundingBox.GetCorners()[1].X + movedistance,
                    allBoundingBox.GetCorners()[1].Y + movedistance,
                    allBoundingBox.GetCorners()[1].Z
                );

                foreach (var geo in AllGeometries)
                {
                    Vector3d translationVector = resultPosition - allBoundingBox.GetCorners()[0];
                    Transform moveTransform = Transform.Translation(translationVector);

                    geo.Transform(moveTransform);
                }

                ObjectAttributes blockAttribute = new ObjectAttributes();
                string _BlockName = $"{BlockName}_DETAY_0";
                var blockLayerIndex =
                    doc.Layers.FindByFullPath(EIAttributesTl.EILayers.PCY_ANNOTATION.DicDim[$"DIM_{TextScale}"], -1);
                blockAttribute.LayerIndex = blockLayerIndex;
                blockAttribute.LayerIndex = blockLayerIndex;


                EIBlocksTl.CreateAndBakeBlock(_BlockName, AllGeometries, AllAttributes, blockAttribute);

                //DA.SetDataList(0, ClosedTrimed);
                //DA.SetDataList(1, outSideCurve);
                //DA.SetDataList(2, inSideCurve);
            }
        }
        public static List<Curve> TrimHatch(Hatch inputHatch, Curve region)
        {
            var doc = RhinoDoc.ActiveDoc;
            List<Curve> outputs = new List<Curve>();
            List<Curve> outSideCurve = new List<Curve>();
            List<Curve> inSideCurve = new List<Curve>();
            outSideCurve.AddRange(inputHatch.Get3dCurves(true));
            inSideCurve.AddRange(inputHatch.Get3dCurves(false));

            var brepRegion = Brep.CreatePlanarBreps(region, 0.001);
            var innerCurveHatchOutside = Curve.ProjectToBrep(outSideCurve, brepRegion, Vector3d.ZAxis, 0.001);
            var innerCurveHatchInside = Curve.ProjectToBrep(inSideCurve, brepRegion, Vector3d.ZAxis, 0.001);

            List<Curve> outSideClosedCurve = new List<Curve>();
            List<Curve> insideClosedCurve = new List<Curve>();
            List<Point3d> centers = new List<Point3d>();

            if (innerCurveHatchOutside.Length > 0)
            {
                outSideClosedCurve.Add(EICurveTI.CloseCurve(innerCurveHatchOutside.ToList()));
                foreach (Curve crv in outSideClosedCurve)
                {
                    var biggetRegion = Brep.CreatePlanarBreps(crv, 0.001);
                    //RhinoDoc.ActiveDoc.Objects.Add(BiggetRegion[0]);
                    Point3d center = AreaMassProperties.Compute(biggetRegion[0]).Centroid;

                    //RhinoDoc.ActiveDoc.Objects.AddPoint(center);
                    centers.Add(center);
                }
            }
            if (innerCurveHatchInside.Length > 0)
            {
                insideClosedCurve.Add(EICurveTI.CloseCurve(innerCurveHatchInside.ToList()));
                foreach (Curve crv in insideClosedCurve)
                {
                    var biggestRegion = Brep.CreatePlanarBreps(crv, 0.001);
                    Point3d center = AreaMassProperties.Compute(biggestRegion[0]).Centroid;
                    centers.Add(center);
                }
            }

            List<Curve> allCurves = new List<Curve>();
            allCurves.AddRange(outSideClosedCurve);
            allCurves.AddRange(insideClosedCurve);

            var currentDocPlane = doc.Views.ActiveView.ActiveViewport.ConstructionPlane();
            var hatchCurves = Curve.CreateBooleanRegions(allCurves, currentDocPlane, centers, false, 0.001);
            var polyline = hatchCurves.RegionCurves(0);
            outputs.AddRange(polyline);

            return outputs;
        }


        public static bool TrimHatch(Hatch inputHatch, Curve region, out List<Curve> trimmedOuterCurves, out List<Curve> trimmedInnerCurves)
        {
            trimmedOuterCurves = new List<Curve>();
            trimmedInnerCurves = new List<Curve>();

            // Extract outer and inner curves from the hatch
            List<Curve> outerCurves = new List<Curve>();
            List<Curve> innerCurves = new List<Curve>();

            // Assume Get3dCurves(true) returns outer curves and Get3dCurves(false) returns inner (hole) curves
            outerCurves.AddRange(inputHatch.Get3dCurves(true));
            innerCurves.AddRange(inputHatch.Get3dCurves(false));

            // Create planar breps from the region
            Brep[] regionBreps = Brep.CreatePlanarBreps(region, RhinoDoc.ActiveDoc.ModelAbsoluteTolerance);
            if (regionBreps == null || regionBreps.Length == 0)
            {
                RhinoApp.WriteLine("Invalid region for trimming hatch.");
                return false;
            }

            Brep regionBrep = regionBreps[0];

            // Trim outer curves
            List<Curve> trimmedOuters = new List<Curve>();
            foreach (var outer in outerCurves)
            {
                var trims = ProjectCurvesToBrep(outer, region);
                trimmedOuters.AddRange(trims);
            }

            // Trim inner curves
            List<Curve> trimmedInners = new List<Curve>();
            foreach (var inner in innerCurves)
            {
                var trims = ProjectCurvesToBrep(inner, region);
                trimmedInners.AddRange(trims);
            }
            // Ensure all trimmed outer curves are closed
            foreach (var crv in trimmedOuters)
            {
                List<Curve> tempListOuter = new List<Curve>();
                tempListOuter.Add(crv);
                if (!crv.IsClosed)
                {
                    Curve cloedOuter = EICurveTI.CloseCurve(tempListOuter);
                    if (cloedOuter != null)
                    {
                        trimmedOuterCurves.Add(cloedOuter);
                    }
                }
                else
                {
                    trimmedOuterCurves.Add(crv);
                }
            }
            // Ensure all trimmed inner curves are closed
            foreach (var crv in trimmedInners)
            {
                List<Curve> tempListInner = new List<Curve>();
                tempListInner.Add(crv);
                if (!crv.IsClosed)
                {
                    Curve cloedInner = EICurveTI.CloseCurve(tempListInner);
                    if (cloedInner != null)
                    {
                        trimmedInnerCurves.Add(cloedInner);
                    }
                }
                else
                {
                    trimmedInnerCurves.Add(crv);
                }
            }
            return true;
        }

        public static List<Curve> ProjectCurvesToBrep(Curve curves, Curve region)
        {
            List<Curve> outPuts = new List<Curve>();
            var BrepRegion = Brep.CreatePlanarBreps(region, 0.001);
            var innerCurveHatchOutside = Curve.ProjectToBrep(curves, BrepRegion, Vector3d.ZAxis, 0.001);
            outPuts.AddRange(innerCurveHatchOutside);
            return outPuts;
        }

        public static List<RhinoObject> FilterObjects(List<RhinoObject> inputList)
        {
            List<RhinoObject> outputObjects = new List<RhinoObject>();
            for (int i = 0; i < inputList.Count; i++)
            {
                //var geometry = inputList[i];
                var rhinoObj = inputList[i] as RhinoObject;
                if (rhinoObj.ObjectType == ObjectType.Annotation)
                {
                    continue;
                }
                else
                {
                    outputObjects.Add(inputList[i]);
                }
            }

            return outputObjects;
        }


        public override Guid ComponentGuid => new Guid("017c89fd-7a68-44c2-8f0a-0f993e62c94a");
    }

}