import FreeCAD as App


from typing import List
from extensions.list import CoreList

from models.vector_model import VectorModel


class FreeCadRepository:
    """Class for handling FreeCAD related functionality"""

    _solids = []

    def openDocument(self, path: str):
        App.open("" + path)

    def closeIfOpenDocument(self):
        """
        If there is an open document being processed in FreeCAD, it may be closed
        """
        try:
            if App.ActiveDocument is not None:
                App.ActiveDocument.clearDocument()
        except Exception as e:
            print(e)

    def getAllLabelsSolids(self) -> List[str]:
        """Returns a list of solid part labels

        Returns:
            List[str]: part labels
        """
        return list(map(lambda el: el.Label, self.getAllSolids()))

    def isAllObjectsSolids(self) -> List[str]:
        """Get all non-solid objects

        Returns:
            List[str]:
        """
        result = []
        for part in App.ActiveDocument.Objects:
            if self.is_object_solid(part) is False:
                result.append(part.Label)
        return result

    def objectSetPosition(self, solid, cadVector):
        solid.Placement.Base = cadVector
        pass

    def objectGetPosition(self, solid) -> VectorModel:
        return VectorModel(cadVector=solid.Placement.Base)

    def isObjectIntersections(self, part) -> str:
        result = []
        for solid in self.getAllSolids():
            if solid.ID != part.ID:
                collisionResult: int = int(part.Shape.distToShape(solid.Shape)[0])
                if collisionResult == 0:
                    result.append(solid.Label)
        if result.__len__() == 0:
            return None
        return result

    def objectHasTouches(self, part, solidBodyPadding: float) -> List[str]:
        try:
            positionVector = self.objectGetPosition(part)
            result = CoreList()
            result.append(self.isObjectIntersections(part=part))
            if solidBodyPadding != 0 and solidBodyPadding != None:
                result.append(
                    self.axis_movement_and_intersections_observer(
                        positionVector=positionVector,
                        alongAxis="x",
                        solidBodyPadding=solidBodyPadding,
                        part=part,
                    )
                )
                result.append(
                    self.axis_movement_and_intersections_observer(
                        positionVector=positionVector,
                        alongAxis="y",
                        solidBodyPadding=solidBodyPadding,
                        part=part,
                    )
                )
                result.append(
                    self.axis_movement_and_intersections_observer(
                        positionVector=positionVector,
                        alongAxis="z",
                        solidBodyPadding=solidBodyPadding,
                        part=part,
                    )
                )
            spreadArr = result.spreadArray()
            if spreadArr.isConstrainsString():
                return spreadArr.getAllString()
            return None
        except Exception as error:
            print(error)
            return None

    def axis_movement_and_intersections_observer(
        self,
        positionVector: VectorModel,
        alongAxis: str,
        solidBodyPadding: float,
        part,
    ) -> bool:
        result = CoreList()
        # UP
        positionVector.__setattr__(
            alongAxis,
            positionVector.__getattribute__(alongAxis) + solidBodyPadding,
        )
        self.objectSetPosition(part, positionVector.toFreeCadVector())
        # result.onlyUniqueElementAppend(self.isObjectIntersections(part=part))
        result.extend(self.isObjectIntersections(part=part))
        # RESET UP CHANGES
        positionVector.__setattr__(
            alongAxis,
            positionVector.__getattribute__(alongAxis) - solidBodyPadding,
        )
        self.objectSetPosition(part, positionVector.toFreeCadVector())

        # DOWN
        positionVector.__setattr__(
            alongAxis,
            positionVector.__getattribute__(alongAxis) - solidBodyPadding,
        )
        self.objectSetPosition(part, positionVector.toFreeCadVector())
        # CHECK DOWN INTERSECTIONS
        # result.onlyUniqueElementAppend(self.isObjectIntersections(part=part))
        result.extend(self.isObjectIntersections(part=part))

        # RESET DOWN CHANGES
        positionVector.__setattr__(
            alongAxis,
            positionVector.__getattribute__(alongAxis) + solidBodyPadding,
        )
        self.objectSetPosition(part, positionVector.toFreeCadVector())
        if result.__len__() == 0:
            return None

        return result.onlyUnique()

    def getAllSolids(self):
        _solids = []

        for part in App.ActiveDocument.Objects:
            if self.is_object_solid(part):
                _solids.append(part)

        return _solids

    def is_object_solid(self, obj):
        if not isinstance(obj, App.DocumentObject):
            return False
        if hasattr(obj, "Group"):
            return False

        if not hasattr(obj, "Shape"):
            return False
        if not hasattr(obj.Shape, "Solids"):
            return False

        if len(obj.Shape.Solids) == 0:
            return False

        return True
