import os
from pygame import Rect, image
import pygame

from utils import load_image

class Block:
    BRICK = "brick"
    GRASS = "grass"
    KUST = "kust"
    STONE = "stone"
    WATER = "water"
    PLAYER_SPAWN = "player_spawn"
    ENEMY_SPAWN = "enemy_spawn"

    def __init__(self, game, x, y, i, j, type: str):
        self.game = game
        self.settings = self.game.settings

        self.height = self.settings.block_size
        self.width = self.settings.block_size
        self.image_folder = os.path.join(self.settings.img_folder, "map")

        self.type = type
        self.passable = self.is_passable()
        self.projectile_passable = self.is_projectile_passable()

        #print(os.path.join(self.image_folder, self.type, ".png"))
        self.image = load_image(self.settings, os.path.join(self.image_folder, self.type + ".png"))
        #print(os.path.join(self.image_folder, self.type + ".png"))

        self.x = x
        self.y = y
        self.i = i
        self.j = j

        self.update()

    def update(self):
        self.rect = self.game.screen.blit(self.image, (self.x, self.y))
    
    def is_passable(self):
        if self.type == "brick" or self.type == "stone" or self.type == "water":
            return False
        else:
            return True
    
    def is_projectile_passable(self):
        if self.type == "brick" or self.type == "stone":
            return False
        else:
            return True
    
    def __str__(self):
        return "{} block on x: {}, y: {}".format(self.type, self.x, self.y)


class Map:
    def __init__(self, game, lc_x: int, lc_y: int):
        self.game = game
        self.settings = game.settings
        self.x = lc_x
        self.y = lc_y

        
        self.charmap = self.load_map("BattleCity.txt")

        self.blockmap = []
        self.enemy_spawns = []
        k = 0
        i = self.y
        j = self.x
        for line in self.charmap:
            self.blockmap.append([])
            j = self.x

            l = 0
            for block in line:
                self.blockmap[k].append(self.get_block_by_char(block, j, i, k, l))

                if block == "P":
                    self.player_spawn = self.blockmap[k][-1]

                if block == "E":
                    self.enemy_spawns.append(self.blockmap[k][-1])

                j += self.settings.block_size
                l += 1

            k += 1
            i += self.settings.block_size
        
        self.enemies = None
        es = self.settings.entity_size
        self.tank_rect = Rect(self.settings.c_x - es // 2, self.settings.c_y - es // 2, es, es)

    def load_map(self, filename: str) -> list:
        f = open(os.path.join(self.settings.map_folder, filename))
        lines = f.readlines()
        f.close()

        i = 0
        result = []
        for line in lines:
            result.append([])
            for c in line:
                if c in "BGKSWPE":
                    result[i].append(c)
            
            i += 1
        
        #print(result)
        return result
    
    def get_block_by_char(self, char, x, y, i, j):
        tp = None

        if char == "B":
            tp = Block.BRICK
        elif char == "G":
            tp = Block.GRASS
        elif char == "K":
            tp = Block.KUST
        elif char == "S":
            tp = Block.STONE
        elif char == "W":
            tp = Block.WATER
        elif char == "P":
            tp = Block.PLAYER_SPAWN
        elif char == "E":
            tp = Block.ENEMY_SPAWN
        
        if tp != None:
            return Block(self.game, x, y, i, j, tp)
        else:
            return False
    
    def add_enemies(self, enemies):
        self.enemies = enemies
    
    def update(self):
        for line in self.blockmap:
            for block in line:
                block.update()
    
    def change_coords(self, x = None, y = None):
        if self.enemies != None:
            dx = self.x - x if x != None else 0
            dy = self.y - y if y != None else 0
            for enemy in self.enemies.sprites():
                enemy.change_coords_by_delta(dx, dy)
            
            for projectile in self.game.projectiles.projectiles:
                projectile.change_coords_by_delta(dx, dy)
        
        k = 0
        self.x = x if x != None else self.x
        self.y = y if y != None else self.y
        j = self.x
        i = self.y

        for line in self.blockmap:
            j = self.x

            for block in line:
                block.x = j
                block.y = i

                j += self.settings.block_size
            
            k += 1
            i += self.settings.block_size
        
        
    
    def get_block_collision_vars(self): #cx, cy, tsh
        return self.settings.c_x, self.settings.c_y, self.settings.block_size // 2


    def move_up(self):
        cx, cy, tsh = self.get_block_collision_vars()
        cp1 = (cx - tsh + 2, cy - tsh)
        cp2 = (cx + tsh - 2, cy - tsh)

        if self.check_on_moveability(cp1[0], cp1[1], 0, self.settings.move_speed) and self.check_on_moveability(cp2[0], cp2[1], 0, self.settings.move_speed):
            self.change_coords(None, self.y + self.settings.move_speed)

    def move_down(self):
        cx, cy, tsh = self.get_block_collision_vars()
        cp1 = (cx - tsh + 2, cy + tsh)
        cp2 = (cx + tsh - 2, cy + tsh)
        
        if self.check_on_moveability(cp1[0], cp1[1], 0, -self.settings.move_speed) and self.check_on_moveability(cp2[0], cp2[1], 0, -self.settings.move_speed):
            self.change_coords(None, self.y - self.settings.move_speed)

    def move_left(self):
        cx, cy, tsh = self.get_block_collision_vars()
        cp1 = (cx - tsh, cy - tsh + 2)
        cp2 = (cx - tsh, cy + tsh - 2)

        if self.check_on_moveability(cp1[0], cp1[1], self.settings.move_speed, 0) and self.check_on_moveability(cp2[0], cp2[1], -self.settings.move_speed, 0):
            self.change_coords(self.x + self.settings.move_speed, None)

    def move_right(self):
        cx, cy, tsh = self.get_block_collision_vars()
        cp1 = (cx + tsh, cy - tsh + 2)
        cp2 = (cx + tsh, cy + tsh - 2)

        if self.check_on_moveability(cp1[0], cp1[1], -self.settings.move_speed, 0) and self.check_on_moveability(cp2[0], cp2[1], -self.settings.move_speed, 0):
            self.change_coords(self.x - self.settings.move_speed, None)
    
    def check_on_moveability(self, x, y, dx, dy):
        #print(x, y, dx, dy)
        #print(self.find_block_on_coords(x + dx, y + dy))
        if self.find_block_on_coords(x, y).passable:
            return True
        else:
            return False

    def find_block_on_coords(self, x, y):
        block_line = None

        for line in self.blockmap:
            if line[0].y <= y and y < line[0].y + self.settings.block_size:
                block_line = line
                break

        
        if block_line != None:
            for block in line:
                if block.x <= x and x < block.x + self.settings.block_size:
                    return block
        
        return False
    
    def __str__(self):
        res = ""
        for line in self.blockmap:
            for block in line:
                res += str(block) + "; "

            res += "\n"

        return res