import base64
import io
import inspect
from  urllib import request

from pyscript import storage, web, when
from PIL import Image

import ant_glitch
# Must register a module with import to be picked up as a subclass
from ant_glitch import (
    copy_region,
    corruption_lines,
    edge,
    enhance,
    inversion_lines,
    pixel_sorts,
    posterize,
    reverblike,
    rgb_rotate,
    rgb_shift,
    rotate,
)


def all_subclasses(cls: type[ant_glitch.BaseFilter]) -> set[type[ant_glitch.BaseFilter]]:
    non_abstract_subclasses = set(
        s for s in cls.__subclasses__() if not inspect.isabstract(s)
    )
    return non_abstract_subclasses.union(
        [
            s
            for c in cls.__subclasses__()
            for s in all_subclasses(c)
            if not inspect.isabstract(s)
        ]
    )


def pillow_image_to_base64_string(img: Image):
    buffered = io.BytesIO()
    img.save(buffered, format="png")
    return base64.b64encode(buffered.getvalue()).decode("utf-8")


ALL_FILTERS = all_subclasses(ant_glitch.BaseFilter)
FILTER_BY_ID: dict[str, type[ant_glitch.BaseFilter]] = {fCls.get_filter_id(): fCls for fCls in ALL_FILTERS}

@when("click", "button.gag-start-processing")
async def main(event):
    try:
        print("Processing in PyScript")
        data = await storage("gag-py")
        with request.urlopen(data["image"]) as resp:
            img_data = resp.read()
            with Image.open(io.BytesIO(img_data)) as im:
                print("Processing then writing result to storage...")
                working_img = im.copy()
                for f_dict in data["filters"]:
                    filter_instance = FILTER_BY_ID[f_dict["id"]].from_filter_dict(f_dict)
                    regions_used = False
                    for sub_region in f_dict.get("regions", []):
                        region_tuple = (
                            ant_glitch.relative_to_absolute_size(
                                working_img.width, sub_region["sX"]
                            ),
                            ant_glitch.relative_to_absolute_size(
                                working_img.height, sub_region["sY"]
                            ),
                            ant_glitch.relative_to_absolute_size(
                                working_img.width, sub_region["dX"]
                            ),
                            ant_glitch.relative_to_absolute_size(
                                working_img.height, sub_region["dY"]
                            ),
                        )
                        working_img = filter_instance.process_region(working_img, region=region_tuple)
                        regions_used = True
                    if not regions_used:
                        working_img = filter_instance.process(working_img)
                print("Done applying filters, returning result dataURL...")
                data["result"] = f"data:image/png;base64,{pillow_image_to_base64_string(working_img)}"
        await data.sync()
    finally:
        for b in web.page.find("button.gag-end-processing"):
            b.click()
            break


@when("click", "button.gag-init-docs-start")
async def set_initial_docs():
    data = await storage("gag-py")
    data["docs"] = {
        fID: {"summary": fCls.get_filter_summary(), "description": fCls.get_filter_description()} for fID, fCls in FILTER_BY_ID.items()
    }
    await data.sync()
    for b in web.page.find("button.gag-init-py-end"):
        b.click()


print("Initialising PyScript inside entry.py")
for b in web.page.find("button.gag-init-docs-start"):
    b.click()
