import os

import numpy as np


def create_cube_mesh(file_name, centre_point, side_len, description=None, verbose=False):
    """
    Creates a cube mesh in wavefront file format.

    Args:
        file_name (str) : Path to output file
        centre_point (float, float, float): Centre of cube
        side_len (float) : Side of cube
        description (str) : Description added to file header
        verbose (bool) : Display extra information

    """

    mesh_dir = os.path.dirname(file_name)
    if len(mesh_dir) > 0 and not os.path.exists(mesh_dir):
        os.makedirs(mesh_dir)

    if type(centre_point) is not np.ndarray:
        centre_point = np.array(centre_point)

    if verbose:
        print("Creating cube mesh")
        print(f"File: {file_name}")
        print(f"Centre: {centre_point}")
        print(f"Side: {side_len}")
        print(f"Description: {description}")

    vertex = np.array([[0.0, 0.0, 0.0],
                       [0.0, 0.0, 1.0],
                       [0.0, 1.0, 0.0],
                       [0.0, 1.0, 1.0],
                       [1.0, 0.0, 0.0],
                       [1.0, 0.0, 1.0],
                       [1.0, 1.0, 0.0],
                       [1.0, 1.0, 1.0]])

    # Centre cube
    vertex -= np.array([0.5, 0.5, 0.5])

    # Scale the cube to right size
    vertex *= side_len

    # Position cube

    vertex += centre_point

    vertex *= 1e6  # The other obj files are in micrometers, so convert :(

    normal_str = "vn  0.0  0.0  1.0\n" \
                 + "vn  0.0  0.0 -1.0\n" \
                 + "vn  0.0  1.0  0.0\n" \
                 + "vn  0.0 -1.0  0.0\n" \
                 + "vn  1.0  0.0  0.0\n" \
                 + "vn -1.0  0.0  0.0\n"

    face_str = "f  1//2  7//2  5//2\n" \
               + "f  1//2  3//2  7//2\n" \
               + "f  1//6  4//6  3//6\n" \
               + "f  1//6  2//6  4//6\n" \
               + "f  3//3  8//3  7//3\n" \
               + "f  3//3  4//3  8//3\n" \
               + "f  5//5  7//5  8//5\n" \
               + "f  5//5  8//5  6//5\n" \
               + "f  1//4  5//4  6//4\n" \
               + "f  1//4  6//4  2//4\n" \
               + "f  2//1  6//1  8//1\n" \
               + "f  2//1  8//1  4//1\n"

    with open(file_name, 'wt') as f:
        f.write("# Generated by create_cube_mesh.py\n")
        f.write(f"# {description}\n\n")

        f.write("g cube\n\n")

        for row in vertex:
            f.write("v %f %f %f\n" % tuple(row))

        f.write(f"\n{normal_str}")

        f.write(f"\n{face_str}")


def cube_cli():
    import argparse

    parser = argparse.ArgumentParser("Create cube mesh for Snudda")
    parser.add_argument("filename", help="Filename of obj file")
    parser.add_argument("side_len", help="Length of the side (units micrometers)", type=float)
    parser.add_argument("--center", "-center", help="Center of cube", default="0,0,0")
    parser.add_argument("--description", help="Description of cube", default=None)

    args = parser.parse_args()

    center = [float(x)*1e-6 for x in args.center.split(",")]

    desc = args.description

    if desc is None:
        desc = f"Cube with side length {args.side_len} micrometers, centered at {args.center}"

    print(f"Creating {args.filename} with side length {args.side_len} micrometers, centered at {args.center}")

    create_cube_mesh(file_name=args.filename,
                     centre_point=center,
                     side_len=args.side_len*1e-6,
                     description=desc)

if __name__ == "__main__":
    cube_cli()
