from typing import Any

from payton.math.vector import min_max
from payton.scene.geometry import Mesh


class Cube(Mesh):
    """
    Cube object

    This is a simple Cube object with width, height and depth.

    Cube object use case:

        .. include:: ../../../examples/basics/02_cube.py

    """

    def __init__(self, **args: Any) -> None:
        """Initialize Cube

        There are two ways to initialize a cube. You can use width, depth,
        height properties or you can specify two distant corners in space
        as `from_corner` and `to_corner`.

        Specifiying corners overwrites width, depth and height.

        Args:
          width: Width of the cube (size X)
          depth: Depth of the cube (size Y)
          height: Height of the cube (size Z)
          from_corner: Starting point of the cube (Optional)
          to_corner: End point of the cube (Optional)
        """
        super().__init__(**args)
        width = args.get("width", 1.0) * 0.5
        depth = args.get("depth", 1.0) * 0.5
        height = args.get("height", 1.0) * 0.5

        if "from_corner" in args and "to_corner" in args:
            from_corner = args.get("from_corner", [0.0, 0.0, 0.0])
            to_corner = args.get("to_corner", [1.0, 1.0, 1.0])
            vmin, vmax = min_max([from_corner, to_corner])

            width = (vmax[0] - vmin[0]) / 2
            depth = (vmax[1] - vmin[1]) / 2
            height = (vmax[2] - vmin[2]) / 2
            self.position = [
                vmin[0] + width,
                vmin[1] + depth,
                vmin[2] + height,
            ]

        _vertices = [
            [width, depth, height],
            [width, depth, -height],
            [width, -depth, height],
            [width, -depth, -height],
            [-width, depth, height],
            [-width, depth, -height],
            [-width, -depth, height],
            [-width, -depth, -height],
        ]

        _normals = [
            [0.0, 0.0, 1.0],
            [0.0, -1.0, 0.0],
            [-1.0, 0.0, 0.0],
            [0.0, 0.0, -1.0],
            [1.0, 0.0, 0.0],
            [0.0, 1.0, 0.0],
        ]

        _texcoords = [
            [0.50, 0.333333],
            [0.25, 0.000000],
            [0.25, 0.333333],
            [1.00, 0.333333],
            [0.75, 0.666666],
            [1.00, 0.666666],
            [0.75, 0.333333],
            [0.50, 0.666666],
            [0.25, 0.666666],
            [0.50, 1.000000],
            [0.50, 0.666666],
            [0.25, 0.333333],
            [0.00, 0.666666],
            [0.25, 0.666666],
            [0.50, 0.333333],
            [0.25, 0.666666],
            [0.50, 0.666666],
            [0.50, 0.000000],
            [0.50, 0.333333],
            [0.25, 1.000000],
            [0.00, 0.333333],
            [0.25, 0.333333],
        ]

        _faces = [
            [[4, 0, 0], [2, 1, 0], [0, 2, 0]],
            [[2, 3, 1], [7, 4, 1], [3, 5, 1]],
            [[6, 6, 2], [5, 7, 2], [7, 4, 2]],
            [[1, 8, 3], [7, 9, 3], [5, 10, 3]],
            [[0, 11, 4], [3, 12, 4], [1, 13, 4]],
            [[4, 14, 5], [1, 15, 5], [5, 16, 5]],
            [[4, 0, 0], [6, 17, 0], [2, 1, 0]],
            [[2, 3, 1], [6, 6, 1], [7, 4, 1]],
            [[6, 6, 2], [4, 18, 2], [5, 7, 2]],
            [[1, 8, 3], [3, 19, 3], [7, 9, 3]],
            [[0, 11, 4], [2, 20, 4], [3, 12, 4]],
            [[4, 14, 5], [0, 21, 5], [1, 15, 5]],
        ]

        i = 0
        for index in _faces:
            ind = []
            for f in index:
                l_vertex = _vertices[f[0]]
                l_normal = _normals[f[2]]
                l_tex = _texcoords[f[1]]
                self._vertices.append(l_vertex)
                self._normals.append(l_normal)
                self._texcoords.append(l_tex)
                ind.append(i)
                i += 1
            self._indices.append(ind)

        return None
