import bpy
import os
from ..utils import force_field
from ..cAPI import SimulationAPI
import numpy as np


class HI_PHY_OT_CreateForceFieldVisualizationMesh(bpy.types.Operator):
    bl_idname = "hi_phy.create_force_field_visualization_mesh"
    bl_label = "Hi Phy Create Force Field Visualization Mesh"
    bl_options = {'REGISTER', 'UNDO_GROUPED'}
    obj: bpy.props.StringProperty(
        default='',
        name='Mesh'
    )
    def execute(self, context):
        mesh = context.scene.objects[self.obj]
        if not mesh or mesh.type != 'MESH':
            self.report({"ERROR"}, "No valid mesh object")
            return {'CANCELLED'}

        hi_phy = mesh.hi_phy
        if not hi_phy.is_active or not hi_phy.object_type == 'FORCE_FIELD':
            self.report({"ERROR"}, self.obj + " is not a valid force field")
            return {'CANCELLED'}

        force_field_evaluator = SimulationAPI.ForceField(hi_phy.ForceFieldExpression, SimulationAPI.ExpressionType.SeExpr)
        if not force_field_evaluator.IsValid():
            self.report({"ERROR"}, self.obj + " do not have a valid expression")
            return {'CANCELLED'}

        x_min = hi_phy.force_field_visualization_x_min
        x_max = hi_phy.force_field_visualization_x_max
        y_min = hi_phy.force_field_visualization_y_min
        y_max = hi_phy.force_field_visualization_y_max
        z_min = hi_phy.force_field_visualization_z_min
        z_max = hi_phy.force_field_visualization_z_max

        x_slice = hi_phy.force_field_visualization_x_slice
        y_slice = hi_phy.force_field_visualization_y_slice
        z_slice = hi_phy.force_field_visualization_z_slice

        if (x_min > x_max or y_min > y_max or z_min > z_max or x_slice < 0 or y_slice < 0 or z_slice < 0):
            self.report({"ERROR"}, "Invalid visualization parameter")
            return {'CANCELLED'}

        dx = (x_max - x_min) / x_slice
        dy = (y_max - y_min) / y_slice
        dz = (z_max - z_min) / z_slice

        points = []
        edges = []
        counter = 0;
        n_samples = x_slice * y_slice * z_slice;
        # Base
        for i in range(x_slice):
            for j in range(y_slice):
                for k in range(z_slice):
                   points.append([x_min + dx * i + dx / 2, y_min + dy * j + dy / 2, z_min + dz * k + dz / 2])
                   edges.append((counter, counter + n_samples))
                   counter = counter + 1

        # Compute Force
        p = np.array(points)
        f = np.zeros((n_samples, 3), dtype=np.float32)

        points_final = force_field.ComputeVisualizationPoints(hi_phy, p, f)
        if (points_final is None):
            self.report({"ERROR"}, "Failed to evaluate the force")
            return {'CANCELLED'}

        # points are in object space
        field = mesh.data
        field.clear_geometry()
        field.from_pydata(points_final, edges, [])
        field.update()

        hi_phy.force_field_visualization_initialized = True;
        return {'FINISHED'}
        
__CLASSES__ = [
    HI_PHY_OT_CreateForceFieldVisualizationMesh
]

def register():
    for class_ in __CLASSES__:
        bpy.utils.register_class(class_)


def unregister():
    for class_ in reversed(__CLASSES__):
        bpy.utils.unregister_class(class_)
