from pathlib import Path

from PIL import Image, ImageChops, ImageDraw, ImageEnhance, ImageFilter, ImageOps


ROOT = Path(__file__).resolve().parent
SOURCE = ROOT / "mapa bolivia2.jpg"
OUTPUT_SIZE = 980

REGIONS = {
    "amazonia": {
        "label": "Amazonia",
        "color": (42, 153, 84),
        "polygon": [
            (0.18, 0.07),
            (0.47, 0.00),
            (0.60, 0.03),
            (0.66, 0.18),
            (0.86, 0.28),
            (0.89, 0.43),
            (0.74, 0.52),
            (0.51, 0.57),
            (0.30, 0.50),
            (0.20, 0.35),
            (0.15, 0.18),
        ],
    },
    "chiquitania": {
        "label": "Chiquitania",
        "color": (237, 183, 45),
        "polygon": [
            (0.61, 0.34),
            (0.83, 0.31),
            (0.96, 0.45),
            (0.99, 0.62),
            (0.87, 0.70),
            (0.65, 0.68),
            (0.54, 0.58),
            (0.55, 0.44),
        ],
    },
    "chaco": {
        "label": "Chaco",
        "color": (206, 91, 45),
        "polygon": [
            (0.55, 0.60),
            (0.74, 0.65),
            (0.97, 0.74),
            (0.87, 0.91),
            (0.70, 0.99),
            (0.50, 0.92),
            (0.46, 0.74),
        ],
    },
    "yungas": {
        "label": "Yungas",
        "color": (36, 128, 172),
        "polygon": [
            (0.19, 0.26),
            (0.28, 0.34),
            (0.36, 0.46),
            (0.49, 0.65),
            (0.45, 0.79),
            (0.35, 0.65),
            (0.27, 0.50),
            (0.20, 0.38),
        ],
    },
}


def is_country_pixel(pixel):
    r, g, b = pixel
    mx = max(pixel)
    mn = min(pixel)
    return (mx - mn > 24 and mx < 252) or (r < 160 and g < 160 and b < 160)


def find_country_box(image):
    pixels = image.load()
    width, height = image.size
    min_x, min_y = width, height
    max_x, max_y = 0, 0

    for y in range(height):
        for x in range(width):
            if is_country_pixel(pixels[x, y]):
                min_x = min(min_x, x)
                min_y = min(min_y, y)
                max_x = max(max_x, x)
                max_y = max(max_y, y)

    pad = 24
    return (
        max(0, min_x - pad),
        max(0, min_y - pad),
        min(width, max_x + pad),
        min(height, max_y + pad),
    )


def make_country_mask(image):
    pixels = image.load()
    width, height = image.size
    mask = Image.new("L", image.size, 0)
    mask_pixels = mask.load()

    for y in range(height):
        for x in range(width):
            if is_country_pixel(pixels[x, y]):
                mask_pixels[x, y] = 255

    mask = mask.filter(ImageFilter.MaxFilter(7))
    mask = mask.filter(ImageFilter.GaussianBlur(1.2))
    return mask


def polygon_mask(size, points):
    width, height = size
    mask = Image.new("L", size, 0)
    draw = ImageDraw.Draw(mask)
    draw.polygon([(x * width, y * height) for x, y in points], fill=255)
    return mask.filter(ImageFilter.GaussianBlur(1.0))


def country_rgba(image, mask):
    rgba = image.convert("RGBA")
    rgba.putalpha(mask)
    return rgba


def muted_base(image, mask):
    gray = ImageOps.grayscale(image).convert("RGB")
    gray = ImageEnhance.Contrast(gray).enhance(1.08)
    gray = ImageEnhance.Brightness(gray).enhance(1.03)
    rgba = gray.convert("RGBA")
    alpha = ImageEnhance.Brightness(mask).enhance(0.72)
    rgba.putalpha(alpha)
    return rgba


def add_design_finish(canvas, mask, title=None):
    shadow = Image.new("RGBA", canvas.size, (0, 0, 0, 0))
    shadow_alpha = mask.filter(ImageFilter.GaussianBlur(16))
    shadow_layer = Image.new("RGBA", canvas.size, (15, 35, 24, 80))
    shadow.paste(shadow_layer, (0, 14), shadow_alpha)
    finished = Image.alpha_composite(shadow, canvas)

    if title:
        draw = ImageDraw.Draw(finished)
        width, height = finished.size
        badge_w = min(width - 80, 360)
        draw.rounded_rectangle(
            (32, 32, 32 + badge_w, 94),
            radius=18,
            fill=(255, 255, 255, 232),
            outline=(28, 44, 28, 70),
            width=2,
        )
        draw.text((56, 52), title, fill=(28, 44, 28))

    return finished


def resize_canvas(image, mask):
    width, height = image.size
    scale = OUTPUT_SIZE / height
    size = (round(width * scale), OUTPUT_SIZE)
    return image.resize(size, Image.Resampling.LANCZOS), mask.resize(size, Image.Resampling.LANCZOS)


def main():
    source = Image.open(SOURCE).convert("RGB")
    cropped = source.crop(find_country_box(source))
    country_mask = make_country_mask(cropped)
    cropped, country_mask = resize_canvas(cropped, country_mask)

    base = muted_base(cropped, country_mask)
    full = base.copy()
    region_masks = {}

    for key, region in REGIONS.items():
        region_masks[key] = polygon_mask(cropped.size, region["polygon"])
        color_layer = Image.new("RGBA", cropped.size, (*region["color"], 188))
        clipped = ImageChops.multiply(country_mask, region_masks[key])
        original = country_rgba(cropped, clipped)
        highlighted = Image.blend(original, color_layer, 0.35)
        highlighted.putalpha(clipped)
        full = Image.alpha_composite(full, highlighted)

    outline = Image.new("RGBA", cropped.size, (0, 0, 0, 0))
    outline_alpha = country_mask.filter(ImageFilter.FIND_EDGES).filter(ImageFilter.MaxFilter(3))
    outline.paste(Image.new("RGBA", cropped.size, (255, 255, 255, 160)), (0, 0), outline_alpha)
    full = Image.alpha_composite(full, outline)
    add_design_finish(full, country_mask).save(ROOT / "bolivia-mapa-completo.png")

    for key, region in REGIONS.items():
        canvas = base.copy()
        clipped = ImageChops.multiply(country_mask, region_masks[key])
        color_layer = Image.new("RGBA", cropped.size, (*region["color"], 205))
        original = country_rgba(cropped, clipped)
        highlighted = Image.blend(original, color_layer, 0.34)
        highlighted.putalpha(clipped)
        canvas = Image.alpha_composite(canvas, highlighted)
        canvas = Image.alpha_composite(canvas, outline)
        add_design_finish(canvas, country_mask).save(ROOT / f"bolivia-{key}.png")


if __name__ == "__main__":
    main()
