import os
import threading
from math import floor
from typing import Optional

import pygame


class ImageHandler:
    def __init__(self, maps_dir: str, base_size: int):
        self.maps_dir: str = maps_dir
        self.base_size: int = base_size
        self.cache: dict = {}
        self.count: int = 0
        self.total: int = 0
        self.loading: bool = False

        t = threading.Thread(target=self.load_base_images)
        t.start()

    def load_base_images(self) -> None:
        cache = {}
        paths = os.listdir(self.maps_dir)
        self.loading = True
        self.count = 0
        self.total = len(paths)
        for path in paths:
            fullpath = os.path.join(self.maps_dir, path)
            name, x, y = path.split(".")[0].split("_")
            cache[(int(x), int(y))] = pygame.image.load(fullpath).convert_alpha()
            self.count += 1

        self.cache = {
            1: cache
        }
        self.loading = False

    def get_for_pos(self, x: int, y: int, zoom: float = 1) -> Optional[pygame.Surface]:
        cache = self.cache.get(zoom, {})
        pos = (x, y)
        if pos not in cache:
            if zoom == 1:
                return None

            # Multiple maps per zone
            elif zoom < 1:
                img = pygame.Surface((self.base_size, self.base_size), pygame.SRCALPHA)
                n_maps = int(1 / zoom)
                sub_size = self.base_size * zoom
                for sub_y in range(n_maps):
                    for sub_x in range(n_maps):
                        sub_img = self.get_for_pos(x * n_maps + sub_x, y * n_maps + sub_y, 1)
                        if sub_img is not None:
                            sub_img = pygame.transform.scale_by(sub_img, zoom)
                            img.blit(sub_img, [sub_x * sub_size, sub_y * sub_size])

            # Zone is part of a map
            else:
                img = self.get_for_pos(floor(x / zoom), floor(y / zoom), 1)
                if img is not None:
                    sub_x = x % zoom
                    sub_y = y % zoom
                    sub_size = self.base_size / zoom
                    img = img.subsurface([sub_x * sub_size, sub_y * sub_size, sub_size, sub_size])
                    img = pygame.transform.scale_by(img, zoom)

            cache[pos] = img

        self.cache[zoom] = cache
        return cache[pos]
