# Light extraction -> glTF KHR_lights_punctual.
#
# glTF punctual lights are point / spot / directional only. Arnold and Maya
# area lights are reported as unsupported instead of being mislabeled as point
# lights. aiSkyDomeLight is also reported separately because Blender does not
# import glTF image-based-light environments.

import math

from maya import cmds


def _short(name):
    return name.split("|")[-1].split(":")[-1]


def _scalar(node, attr, default=0.0):
    try:
        if cmds.attributeQuery(attr, node=node, exists=True):
            return float(cmds.getAttr(node + "." + attr))
    except Exception:
        pass
    return default


def _color(shape):
    try:
        c = cmds.getAttr(shape + ".color")[0]
        return [max(0.0, float(c[0])), max(0.0, float(c[1])), max(0.0, float(c[2]))]
    except Exception:
        return [1.0, 1.0, 1.0]


def _world_matrix(shape):
    parents = cmds.listRelatives(shape, parent=True, fullPath=True) or []
    if not parents:
        return None
    try:
        return [float(v) for v in cmds.getAttr(parents[0] + ".worldMatrix[0]")]
    except Exception:
        return None


# Blender importer: point/spot watts = candela * 4*pi / 683; sun = lux / 683.
# These factors give Maya-intensity-1 lights a sensible default wattage.
_PSCALE = 683.0 / (4.0 * math.pi)   # ~54.35
_DSCALE = 683.0


def _entry(shape, light):
    m = _world_matrix(shape)
    if not m:
        return None
    return {"name": _short(shape), "matrix": m, "light": light}


def extract_lights(opts):
    # Returns a list of {"name", "matrix", "light"} for every supported light.
    out = []
    if not opts.get("include_lights", True):
        return out

    for shape in (cmds.ls(type="pointLight") or []):
        candela = max(0.0, _scalar(shape, "intensity", 1.0) * _PSCALE)
        e = _entry(shape, {"type": "point", "name": _short(shape),
                           "color": _color(shape), "intensity": candela})
        if e:
            out.append(e)

    for shape in (cmds.ls(type="spotLight") or []):
        candela = max(0.0, _scalar(shape, "intensity", 1.0) * _PSCALE)
        cone = _scalar(shape, "coneAngle", 40.0)
        penumbra = _scalar(shape, "penumbraAngle", 0.0)
        outer = math.radians(cone * 0.5)
        inner = max(0.0, math.radians((cone * 0.5) - max(0.0, penumbra)))
        if inner >= outer:
            inner = max(0.0, outer - 0.01)
        e = _entry(shape, {"type": "spot", "name": _short(shape),
                           "color": _color(shape), "intensity": candela,
                           "spot": {"innerConeAngle": inner, "outerConeAngle": outer}})
        if e:
            out.append(e)

    for shape in (cmds.ls(type="directionalLight") or []):
        lux = max(0.0, _scalar(shape, "intensity", 1.0) * _DSCALE)
        e = _entry(shape, {"type": "directional", "name": _short(shape),
                           "color": _color(shape), "intensity": lux})
        if e:
            out.append(e)

    return out


def find_unsupported_lights(opts):
    result = {"area_lights": [], "skydomes": []}
    if not opts.get("include_lights", True):
        return result

    for node_type in ("aiAreaLight", "areaLight"):
        for shape in (cmds.ls(type=node_type, long=True) or []):
            result["area_lights"].append(shape)

    for shape in (cmds.ls(type="aiSkyDomeLight", long=True) or []):
        hdri = None
        for history_node in (cmds.listHistory(shape) or []):
            for attr in ("fileTextureName", "filename"):
                try:
                    if cmds.attributeQuery(attr, node=history_node, exists=True):
                        path = cmds.getAttr("{0}.{1}".format(history_node, attr))
                        if path:
                            hdri = path
                            break
                except Exception:
                    pass
            if hdri:
                break
        result["skydomes"].append({"shape": shape, "hdri": hdri})
    return result


def find_hdri(opts):
    # Returns (skydome_node, exr_path) for the first aiSkyDomeLight, or (None, None).
    # glTF cannot carry an environment that Blender imports; this is for the
    # report so the user knows to load it manually.
    for shape in (cmds.ls(type="aiSkyDomeLight") or []):
        for h in (cmds.listHistory(shape) or []):
            for attr in ("fileTextureName", "filename"):
                if cmds.attributeQuery(attr, node=h, exists=True):
                    path = cmds.getAttr(h + "." + attr)
                    if path:
                        return shape, path
        return shape, None
    return None, None
