try:
    import importlib.resources as pkg_resources
except ImportError:
    # Try backported to PY<37 `importlib_resources`.
    import importlib_resources as pkg_resources
from . import images

from gym import Env, spaces

from time import time
import numpy as np
from copy import copy
import colorsys

import pygame
from pygame.transform import scale

class MinesweeperEnv(Env):

    def __init__(self, grid_shape=(10, 15), bombs_density=0.1, n_bombs=None, impact_size=3, max_time=999, chicken=False):
        self.grid_shape = grid_shape
        self.grid_size = np.prod(grid_shape)
        self.n_bombs = max(1, int(bombs_density * self.grid_size)) if n_bombs is None else n_bombs
        self.n_bombs = min(self.grid_size - 1, self.n_bombs)
        self.flaged_bombs = 0
        self.flaged_empty = 0
        self.max_time = max_time

        if impact_size % 2 == 0:
            raise ValueError('Impact_size must be an odd number !')
        self.impact_size = impact_size

        # Define constants
        self.HIDDEN = 0
        self.REVEAL = 1
        self.FLAG = 2
        self.BOMB = self.impact_size ** 2
        
        # Setting up gym Env conventions
        nvec_observation = (self.BOMB + 2) * np.ones(self.grid_shape)
        self.observation_space = spaces.MultiDiscrete(nvec_observation)

        nvec_action = np.array(self.grid_shape + (2,))
        self.action_space = spaces.MultiDiscrete(nvec_action)

        # Initalize state
        self.state = np.zeros(self.grid_shape + (2,), dtype=np.uint8)

        ## Setup bombs places
        idx = np.indices(self.grid_shape).reshape(2, -1)
        bombs_ids = np.random.choice(range(self.grid_size), size=self.n_bombs, replace=False)
        self.bombs_positions = idx[0][bombs_ids], idx[1][bombs_ids]

        ## Place numbers
        self.semi_impact_size = (self.impact_size-1)//2
        bomb_impact = np.ones((self.impact_size, self.impact_size), dtype=np.uint8)
        for bombs_id in bombs_ids:
            bomb_x, bomb_y = idx[0][bombs_id], idx[1][bombs_id]
            x_min, x_max, dx_min, dx_max = self.clip_index(bomb_x, 0)
            y_min, y_max, dy_min, dy_max = self.clip_index(bomb_y, 1)
            bomb_region = self.state[x_min:x_max, y_min:y_max, 0]
            bomb_region += bomb_impact[dx_min:dx_max, dy_min:dy_max]

        ## Place bombs
        self.state[self.bombs_positions + (0,)] = self.BOMB
        self.start_time = time()
        self.time_left = int(time() - self.start_time)

        # Setup rendering
        self.pygame_is_init = False
        self.chicken = chicken
        self.done = False
        self.score = 0

    def get_observation(self):
        observation = copy(self.state[:, :, 1])

        revealed = observation == 1
        flaged = observation == 2

        observation += self.impact_size ** 2 + 1
        observation[revealed] = copy(self.state[:, :, 0][revealed])

        observation[flaged] -= 1
        return observation

    def reveal_around(self, coords, reward, done, without_loss=False):
        if not done:
            x_min, x_max, _, _ = self.clip_index(coords[0], 0)
            y_min, y_max, _, _ = self.clip_index(coords[1], 1)

            region = self.state[x_min:x_max, y_min:y_max, :]
            unseen_around = np.sum(region[..., 1] == 0)
            if unseen_around == 0:
                if not without_loss: 
                    reward -= 0.001
                return

            flags_around = 
np.sum(region[..., 1] == 2)