from __future__ import annotations

import numpy as np

from comfy_api.latest import ComfyExtension, io
from comfy_api.input import CurveInput
from typing_extensions import override


class CurveEditor(io.ComfyNode):
    @classmethod
    def define_schema(cls):
        return io.Schema(
            node_id="CurveEditor",
            display_name="Curve Editor",
            category="utils",
            inputs=[
                io.Curve.Input("curve"),
                io.Histogram.Input("histogram", optional=True),
            ],
            outputs=[
                io.Curve.Output("curve"),
            ],
        )

    @classmethod
    def execute(cls, curve, histogram=None) -> io.NodeOutput:
        result = CurveInput.from_raw(curve)

        ui = {}
        if histogram is not None:
            ui["histogram"] = histogram if isinstance(histogram, list) else list(histogram)

        return io.NodeOutput(result, ui=ui) if ui else io.NodeOutput(result)


class ImageHistogram(io.ComfyNode):
    @classmethod
    def define_schema(cls):
        return io.Schema(
            node_id="ImageHistogram",
            display_name="Image Histogram",
            category="utils",
            inputs=[
                io.Image.Input("image"),
            ],
            outputs=[
                io.Histogram.Output("rgb"),
                io.Histogram.Output("luminance"),
                io.Histogram.Output("red"),
                io.Histogram.Output("green"),
                io.Histogram.Output("blue"),
            ],
        )

    @classmethod
    def execute(cls, image) -> io.NodeOutput:
        img = image[0].cpu().numpy()
        img_uint8 = np.clip(img * 255, 0, 255).astype(np.uint8)

        def bincount(data):
            return np.bincount(data.ravel(), minlength=256)[:256]

        hist_r = bincount(img_uint8[:, :, 0])
        hist_g = bincount(img_uint8[:, :, 1])
        hist_b = bincount(img_uint8[:, :, 2])

        # Average of R, G, B histograms (same as Photoshop's RGB composite)
        rgb = ((hist_r + hist_g + hist_b) // 3).tolist()

        # ITU-R BT.709-6, Item 3.2 (p.6) — Derivation of luminance signal
        # https://www.itu.int/rec/R-REC-BT.709-6-201506-I/en
        lum = 0.2126 * img[:, :, 0] + 0.7152 * img[:, :, 1] + 0.0722 * img[:, :, 2]
        luminance = bincount(np.clip(lum * 255, 0, 255).astype(np.uint8)).tolist()

        return io.NodeOutput(
            rgb,
            luminance,
            hist_r.tolist(),
            hist_g.tolist(),
            hist_b.tolist(),
        )


class CurveExtension(ComfyExtension):
    @override
    async def get_node_list(self):
        return [CurveEditor, ImageHistogram]


async def comfy_entrypoint():
    return CurveExtension()
