import json
import os
import random
from PIL import Image

# Local imports
from src.texturepack_utils import scanPacksForTexture
from src.utilities import printOverride

def generateTexture(root, infile, useProgrammerArt=False):
    outfolder = root.replace("assets", "").replace("input", "assets")
    os.makedirs(outfolder, exist_ok=True)

    # Check for texture stitching data
    textureMap = createTextureMap(root, infile, useProgrammerArt)

    root = scanPacksForTexture(root, infile)
    if useProgrammerArt: root = scanPacksForTexture(root, infile, "./input/programmer_art")

    outfile = os.path.splitext(os.path.join(outfolder, infile))[0] + ".png"
    if infile != outfile:
        try:
            stitchTexture(textureMap, root, infile, outfile)
        except IOError:
            print("Error while generating texture for '%s'" % infile)

def createTextureMap(root, infile, useProgrammerArt):
    textureMap = {}
    if os.path.isfile(os.path.join(root, infile.replace(".png", ".betterleaves.json"))):
        with open(os.path.join(root, infile.replace(".png", ".betterleaves.json")), "r") as f:
            json_data = json.load(f)
            if "textureStitching" in json_data:
                printOverride("Using texture stitching data from: " + f.name)
                # Create texture map from stitching data
                for key, value in json_data["textureStitching"].items():
                    if "-" in key:
                        for i in range(int(key.split("-")[0]), int(key.split("-")[1])+1): textureMap[str(i)] = value
                    else: textureMap[key] = value
                # Turn texture map into absolute paths
                for key, value in textureMap.items():
                    textureRoot = f"./input/assets/{value.split(':')[0]}/textures/"
                    textureFile = value.split(":")[1] + ".png"
                    if "/" in textureFile:
                        textureRoot += textureFile.rsplit("/")[0]
                        textureFile = textureFile[len(textureFile.rsplit("/")[0])+1:] # The rest of the string, starting behind the first '/'
                    textureRoot = scanPacksForTexture(textureRoot, textureFile)
                    if useProgrammerArt: root = scanPacksForTexture(textureRoot, textureFile, "./input/programmer_art")
                    textureMap[key] = os.path.join(textureRoot, textureFile)
    return textureMap

def stitchTexture(textureMap, root, infile, outfile):
    # First, let's open the regular texture
    vanilla = Image.open(os.path.join(root, infile))
    width, height = vanilla.size
    # Second, let's generate a transparent texture that's twice the size
    transparent = Image.new("RGBA", [int(2 * s) for s in vanilla.size], (255, 255, 255, 0))
    out = transparent.copy()

    # Now we paste the regular texture in a 3x3 grid, centered in the middle
    for x in range(-1, 2):
        for y in range(-1, 2):
            texture = vanilla
            index = (x + 2) + (y + 1) * 3 # Turns coordinates into a number from 1 to 9
            if str(index) in textureMap: # Load texture from texture stitching map
                texture = Image.open(textureMap[str(index)])
            out.paste(texture, (int(width / 2 + width * x), int(height / 2 + height * y)))

    # As the last step, we apply our custom mask to round the edges and smoothen things out
    mask_location = f"input/masks/{width}px" # If possible, use a mask designed for the texture's size
    if not os.path.isdir(mask_location) or len(os.listdir(mask_location)) == 0: mask_location = "input/masks/16px"
    random.seed(infile) # Use the filename as a seed. This ensures we always get the same mask per block.
    mask_location += f"/{random.choice(os.listdir(mask_location))}" # Choose a random mask to get some variation between the different types of leaves
    mask = Image.open(mask_location).convert('L').resize(out.size, resample=Image.NEAREST)
    out = Image.composite(out, transparent, mask)

    # Finally, we save the texture to the assets folder
    out.save(outfile, vanilla.format)
