import json
import os
from pathlib import Path

import numpy as np
from matplotlib import colormaps
from PIL import Image as PImage


def create_animation_file(path, filelist):
    data_json = json.dumps(filelist)
    content_js = f"const animationFrames = {data_json};\n"
    with open(path, "w", encoding="utf-8", newline="\n") as file:
        file.write(content_js)


def create_palette_image(palette_bytes):
    palette_image = PImage.new("P", (1, 1))
    palette_image.putpalette(palette_bytes)

    return palette_image


def create_gif_palette(cmap_names, colors_per_cmap):
    palette_rgb = []
    for i, cmap_name in enumerate(cmap_names):
        cmap = colormaps.get_cmap(cmap_name)
        # Obtener colores RGB normalizados (entre 0 y 1)
        colors_normalized = cmap(np.linspace(0, 1, colors_per_cmap[i]))
        # Convertir a valores enteros entre 0 y 255
        colors_rgb = (colors_normalized[:, :3] * 255).astype(np.uint8)
        palette_rgb.extend(colors_rgb.flatten().tolist())

    return bytes(palette_rgb)


def create_animation(
    media_list, output_path, cmaps=None, fps=None, interval=None, loop=True
):
    # Check for empty path list
    if not media_list:
        print("ERROR: Empty file list!")
        return False

    # Determine the duration of each photogram in ms
    if fps is not None and fps > 0:
        duration_ms = int(1000 / fps)
    elif interval is not None and interval > 0:
        duration_ms = interval
    else:
        duration_ms = 200

    if cmaps is not None:
        n_cmap = len(cmaps)
        colors_size = 256 // n_cmap
        colors_total = colors_size * n_cmap
        colors_per_cmap = [colors_size] * n_cmap
        k = 0
        while colors_total < 256:
            colors_per_cmap[k] += 1
            colors_total += 1
            k = (k + 1) % n_cmap

        # Generar los bytes de la paleta precalculada
        precalculated_palette_bytes = create_gif_palette(
            cmaps, colors_per_cmap
        )

        # Crear una imagen de paleta dummy
        palette_image = create_palette_image(precalculated_palette_bytes)

    # Read the images
    images = []
    for i, file_name in enumerate(media_list):
        if not os.path.exists(file_name):
            print(f"File '{file_name}' does not exist!")
            continue
        try:
            img = PImage.open(file_name).convert("RGB")
            if cmaps is not None:
                # Convertir a modo paleta utilizando la paleta precalculada
                img_p = img.quantize(
                    palette=palette_image, dither=PImage.FLOYDSTEINBERG
                )
                images.append(img_p)
            else:
                images.append(img)
        except Exception as e:
            print(f"File '{file_name}' is corrupted: {e}")

    # Create the animated GIF
    if not images:
        print("ERROR: Empty image list!")
        return False

    # The first frame is the base
    first = images[0]

    # The remaining frames will be added
    remaining = images[1:]

    # Determine the loop parameter value
    # 0=infinite, 1=once
    loop_value = 0 if loop else 1

    generated_by = (
        "Generated by GOES-CORE (https://github.com/wvenialbo/GOES-CORE/)."
    )

    try:
        output_path = Path(output_path)

        if output_path.suffix == ".gif":
            first.save(
                output_path,
                save_all=True,
                append_images=remaining,
                optimize=True,
                # include_color_table=True,
                # palette=0,
                disposal=2,
                loop=loop_value,
                duration=duration_ms,
                comment=generated_by.encode("utf-8"),
            )
        elif output_path.suffix == ".png":
            info = PngInfo()
            info.add_text("Comment", generated_by.encode("utf-8"))
            first.save(
                output_path,
                save_all=True,
                append_images=remaining,
                optimize=True,
                loop=loop_value,
                duration=duration_ms,
                disposal=0,
                blend=0,
                pnginfo=info,
            )
        elif output_path.suffix == ".webp":
            user_comment = b"UNICODE\x00" + generated_by.encode("utf-8")
            exif = PImage.Exif()
            exif[37510] = user_comment
            first.save(
                output_path,
                save_all=True,
                append_images=remaining,
                duration=duration_ms,
                loop=loop_value,
                # lossless=True,
                # quality=100,
                # method=6,
                exif=exif.tobytes(),
            )
        else:
            raise ValueError(f"Unexpected format '{output_path.suffix}'")
        return True

    except Exception as e:
        print(f"ERROR: Unable to create the animation: {e}")
        return False
