using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using uBIMEarthTools.Utils;

namespace uBIMEarthTools.PileCheck
{
    [Transaction(TransactionMode.Manual)]
    public class PileCheckCommand : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UIDocument uIDocument = commandData.Application.ActiveUIDocument;
            Document document = uIDocument.Document;
            if (!(document.ActiveView is View3D))
            {
                System.Windows.Forms.MessageBox.Show($"请在三维视图下操作");
                return Result.Failed;
            }

            Document linkDocument = new FilteredElementCollector(document, document.ActiveView.Id).OfClass(typeof(RevitLinkInstance)).Cast<RevitLinkInstance>().FirstOrDefault().GetLinkDocument();
            List<string> bearingStratum = new FilteredElementCollector(linkDocument).OfClass(typeof(FamilySymbol)).Where(x => x.Name.Contains("地质")).Select(x => x.Name).ToList();
            PileCheckWindow pileCheckWindow = new PileCheckWindow(bearingStratum);

            pileCheckWindow.ShowDialog();
            if (pileCheckWindow.DialogResult != true)
            {
                return Result.Cancelled;
            }
            List<PileParametersEntity> pileParametersEntities = pileCheckWindow.PileItems.ToList();

            BoundingBoxXYZ boundingBox = (document.ActiveView as View3D).GetSectionBox();
            double maxZ = boundingBox.Min.Z > boundingBox.Max.Z ? boundingBox.Min.Z : boundingBox.Max.Z;
            double minZ = boundingBox.Min.Z < boundingBox.Max.Z ? boundingBox.Min.Z : boundingBox.Max.Z;
            ReferenceIntersector referenceIntersector = new ReferenceIntersector(document.ActiveView as View3D);
            referenceIntersector.FindReferencesInRevitLinks = true;
            Random random = new Random();


            Family family = (new FilteredElementCollector(document).OfCategory(BuiltInCategory.OST_GenericModel)
                       .OfClass(typeof(FamilySymbol)).First(x => x.Name == "桩") as FamilySymbol).Family;
            Autodesk.Revit.DB.Document fdoc = document.EditFamily(family);
            Transaction trans = new Transaction(fdoc);
            trans.Start("Create FamilySymbol");
            if (null != fdoc)
            {
                FamilyManager fm = fdoc.FamilyManager;
                foreach (string type in pileParametersEntities.GroupBy(x => x.Type).Select(x => x.Key))
                {
                    try
                    {
                        FamilyType ft = fm.NewType(type);
                    }
                    catch
                    {
                        continue;
                    }
                }

            }

            LoadOpts loadOptions = new LoadOpts();
            family = fdoc.LoadFamily(document, loadOptions);
            trans.Commit();


            trans = new Transaction(document);
            trans.Start("Create Instance");

            foreach (PileParametersEntity item in pileParametersEntities)
            {
                XYZ xyz = new XYZ(item.LocationX * 1000 / 304.8, item.LocationY * 1000 / 304.8, maxZ + 10);
                List<ReferenceWithContext> referenceWithContexts = referenceIntersector.Find(xyz, -XYZ.BasisZ).Where(x => x.GetReference().ElementReferenceType != ElementReferenceType.REFERENCE_TYPE_NONE).ToList();
                double depth = maxZ - minZ + 50;
                if (referenceWithContexts.Count() != 0)
                {
                    double height = referenceWithContexts.OrderBy(x => x.Proximity).First().Proximity;
                    xyz = new XYZ(xyz.X, xyz.Y, xyz.Z - height);

                    if (referenceWithContexts.Any(x => linkDocument.GetElement(x.GetReference().LinkedElementId)?.Name == item.SelectedBearingStratumItem))
                    {
                        depth = referenceWithContexts.FirstOrDefault(x => linkDocument.GetElement(x.GetReference().LinkedElementId).Name == item.SelectedBearingStratumItem).Proximity;
                        depth = depth - height;
                    }

                }

                double depthOfRock = random.NextDouble() * (item.DepthOfRockMax - item.DepthOfRockMin) / 304.8;
                depth += depthOfRock;
                FamilySymbol familySymbol = new FilteredElementCollector(document)
                                .OfCategory(BuiltInCategory.OST_GenericModel).OfClass(typeof(FamilySymbol))
                                .First(x => x.Name == item.Type) as FamilySymbol;
                if (!familySymbol.IsActive)
                {
                    familySymbol.Activate();
                }

                FamilyInstance familyInstance = document.Create.NewFamilyInstance(xyz, familySymbol, StructuralType.NonStructural);
                familyInstance.LookupParameter("区域").Set(item.Region);
                familyInstance.LookupParameter("地块编号").Set(item.Number);
                familyInstance.LookupParameter("坐标X").Set(item.LocationX.ToString());
                familyInstance.LookupParameter("坐标Y").Set(item.LocationY.ToString());
                familyInstance.LookupParameter("直径").Set(item.Diameter / 304.8);
                familyInstance.LookupParameter("深度").Set(depth);
                familyInstance.LookupParameter("入岩深度").Set(depthOfRock);
            }

            trans.Commit();

            return Result.Succeeded;
        }

        /// <summary>
        /// 创建模型线圆
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="centerPoint"></param>
        /// <returns></returns>
        public static ElementId CreateModelArc(Autodesk.Revit.DB.Document doc, XYZ centerPoint, double r)
        {
            XYZ normal = new XYZ(0, 0, 1);
            double radius = r / 304.8;
            double startAngle = 0;
            double endAngle = 2 * Math.PI;

            Plane geomPlane = Plane.CreateByNormalAndOrigin(normal, XYZ.Zero);
            Arc arc = Arc.Create(geomPlane, radius, startAngle, endAngle);
            SketchPlane sketch = SketchPlane.Create(doc, geomPlane);
            ModelArc modelArc = doc.Create.NewModelCurve(arc, sketch) as ModelArc;
            ElementTransformUtils.MoveElement(doc, modelArc.Id, centerPoint);
            return modelArc.Id;
        }
    }
}
