from typing import Union, Iterable
import os
import PIL
import PIL.GifImagePlugin
import PIL.Image

from .. import Func
from ..Graphic import Animation, Pixel
from ..Classes import Buffer


class AnimationManager:
    _animations: dict[str, Animation] = {}

    @classmethod
    def get(cls, name: str) -> Animation:
        if name not in cls._animations:
            raise ValueError(f'Animation "{name}" not found')
        return cls._animations[name].copy()
    
    @classmethod
    def register(cls, name: str, animation: Animation):
        if name in cls._animations:
            raise ValueError('//')
        cls._animations[name] = animation
    
    @classmethod
    def load(cls, path: str):
        '''
            Path to a json file with data like:\n
            [
                {
                    name: `str` - animation name,
                    path: `str` - path to img/jpg/jpeg/gif,
                    delay: `float` default=get from source file - delay between frames,
                    loop: `bool` default=True - animation is looped
                }, \n
                ...
            ]
        '''
        dir_path = os.path.dirname(path)
        
        animations_data: list[dict[str, any]] = Func.readJson(path)
        for data in animations_data:
            image = PIL.Image.open(f'./{dir_path}/{data['path']}', formats=['png', 'jpeg', 'gif'])
            
            cls.register(
                data['name'],
                Animation(
                    delay=data.get('delay', cls.getDelay(image)),
                    loop=data.get('loop', True),
                    frames=cls.getFrames(image)
                )
            )
    
    @classmethod
    def getDelay(cls, image: Union[PIL.Image.Image, PIL.GifImagePlugin.GifImageFile]) -> float:
        if isinstance(image, PIL.GifImagePlugin.GifImageFile):
            return image.info.get('duration') / 1000
        return 0
    
    @classmethod
    def getFrames(cls, image: Union[PIL.Image.Image, PIL.GifImagePlugin.GifImageFile]) -> Iterable[Buffer[Pixel]]:
        def convertImageToBuffer(image: Union[PIL.Image.Image, PIL.GifImagePlugin.GifImageFile]) -> Buffer[Pixel]:
            return Buffer(
                image.width,
                image.height,
                None,
                [
                    Pixel(back_color=pixel_data[:3]) if pixel_data[3] > 125 else None for pixel_data in image.convert('RGBA').getdata()
                ]
            )
        
        if isinstance(image, PIL.GifImagePlugin.GifImageFile):
            frames = []
            for i in range(image.n_frames):
                image.seek(i)
                frames.append(
                    convertImageToBuffer(image)
                )
            return frames
        
        else:
            return [
                Buffer(
                    image.width,
                    image.height,
                    None,
                    convertImageToBuffer(image)
                )
            ]
                
    