from PIL import Image, ImageOps, ImageDraw, ImageChops
from io import BytesIO
from glob import glob
import numpy as np
import base64
import os

def base64_to_img(base64_bytes: bytes) -> Image:
    img_bytes = base64.b64decode(base64_bytes)
    img_buffer = BytesIO(img_bytes)
    img = Image.open(img_buffer)
    img = img.convert("RGBA")
    return img

def img_to_array(img: Image) -> np.array:
    img_array = np.array(img)
    return img_array

def _avg_colors(img: Image) -> tuple:
    img_array = img_to_array(img)
    avg_colors = np.mean(img_array, axis=tuple(range(img_array.ndim - 1)))
    avg_list = list(map(int, avg_colors))
    avg_list[3] = 255
    return tuple(avg_list)

def __avg_colors(pil_img):
    img = pil_img.copy()
    img.convert("RGB")
    img.resize((1, 2), resample=0)
    dominant_color = img.getpixel((0, 0))
    print(img.getpixel((0, 1)))
    return dominant_color

def avg_colors(img):
    img_array = img_to_array(img)
    colors, count = np.unique(img_array.reshape(-1,img_array.shape[-1]), axis=0, return_counts=True)

    return tuple(colors[count.argmax()])


def add_background(img: Image, bg_tuple: tuple) -> Image:
    bg = Image.new("RGBA", img.size, bg_tuple)
    bg.paste(img, (0, 0), img)
    return bg

def crop_to_circle(im, template):
    im = im.copy()
    bigsize = (im.size[0] * 3, im.size[1] * 3)
    mask = Image.new('L', bigsize, 0)
    ImageDraw.Draw(mask).ellipse((0, 0) + bigsize, fill=255)
    midsize = tuple(x//2 for x in bigsize)
    if template[0] == 1:
        ImageDraw.Draw(mask).rectangle((0, 0) + midsize, fill=255)
    if template[1] == 1:
        ImageDraw.Draw(mask).rectangle((midsize[0], 0, bigsize[0], midsize[1]), fill=255)
    if template[2] == 1:
        ImageDraw.Draw(mask).rectangle((0, midsize[1], midsize[1], bigsize[1]), fill=255)
    if template[3] == 1:
        ImageDraw.Draw(mask).rectangle(midsize + bigsize, fill=255)
    mask = mask.resize(im.size, Image.ANTIALIAS)
    mask = ImageChops.darker(mask, im.split()[-1])
    im.putalpha(mask)
    return im

def parse_file(desktop_path):
    output = {}
    with open(desktop_path, "r") as f:
        for line in f:
            if not line:
                continue
            if line.startswith("["):
                continue
            key, value = line.split("=", 1)
            output[key] = value.strip()
    output["path"] = desktop_path
    return output

def deparse_file(app):
    output = ["[Desktop Entry]"]
    for key, value in app.items():
        output.append(f"{key}={value}")
    return "\n".join(output)

def get_web_icons():
    path = os.path.join(
        os.path.expanduser("~"),
        ".local",
        "share",
        "applications",
        "sailfish-browser*.desktop"
    )
    return glob(path)

def sailify(raw_str, pattern):
    base64_bytes = raw_str.replace("data:image/png;base64,", "", 1).encode()
    img = base64_to_img(base64_bytes)
    bg_tuple = avg_colors(img)
    img = add_background(img, bg_tuple)
    img = crop_to_circle(img, pattern)
    output_buffer = BytesIO()
    img.save(output_buffer, format="PNG")
    output_data = output_buffer.getvalue()
    output_base64 = base64.b64encode(output_data)
    return "data:image/png;base64," + output_base64.decode()

def main():
    import shutil

    while True:
        apps = get_web_icons()
        apps = list(map(parse_file, apps))
        while True:
            for n, app in enumerate(apps):
                print(f"{n}) {app['Name']}")
            index = input("select an application (the index):\n>>> ")
            index = int(index)
            if index >= len(apps):
                print("Select a valid index")
                continue
            break
        app = apps[index]
        while True:
            pattern = input("Enter the pattern (0 = round, 1 = peak):\n>>> ")
            if len(pattern) != 4:
                print("it is necessary to enter 4 characters")
            pattern = tuple(map(int, pattern))
            new_icon = sailify(app.get("old_icon", app["Icon"]), pattern)
            # Backup the original .desktop
            shutil.copyfile(app["path"], app["path"] + "_backup")
            app["old_icon"] = app.get("old_icon", app["Icon"])
            app["Icon"] = new_icon
            new_content = deparse_file(app)
            with open(app["path"], "w") as f:
                f.write(new_content)
            print(f"{app['Name']} sailified correctly")
            break


if __name__ == "__main__":
    main()