from settings import *
import pygame as pg
from pygame.math import Vector2 as vector
from support import load_all_images, import_maps, Sproot, return_y, player_is_blocked_by_object
import sys
import os
from bite import *


def setup_area(map, player_start_pos):
    
    # initialize list of sprites
    bg_sprites, main_sprites, fg_sprites, animated_sprites, collidable_sprites, nomekop_sprites = [], [], [], [], [], []

    # get terrain tiles
    terrain = map.get_layer_by_name("Terrain")
    for x, y, surface in terrain.tiles():
        position = (x * TILE_SIZE, y * TILE_SIZE)
        s = Sproot(surface, surface.get_frect(topleft = position))
        bg_sprites.append(s)

    # get water tiles
    water = map.get_layer_by_name("Water")
    path = os.path.join("..", "graphics", "tilesets", "water.png")
    water_images = load_all_images(path, 1, 4)
    for w in water:
        position = (w.x, w.y)
        s = Sproot()
        s.image = water_images[0]
        s.rect = s.image.get_frect(topleft = position)
        s.all_images = water_images
        bg_sprites.append(s)
        animated_sprites.append(s)

    # get coast tiles
    terrain_types = ["grass", "grass_i", "sand_i", "sand", "rock", "rock_i", "ice", "ice_i"]
    sides = ["topleft", "top", "topright", "left", "right", "bottomleft", "bottom", "bottomright"]
    coast_images = {}
    for t in terrain_types:
        for s in sides:
            ts = f"{t}_{s}"
            path = os.path.join("..", "graphics", "tilesets", f"{ts}.png")
            coast_images[ts] =  load_all_images(path, 1, 4)
    coast = map.get_layer_by_name("Coast")
    for c in coast:
        position = (c.x, c.y)
        t = c.terrain
        s = c.side
        ts = f"{t}_{s}"
        s = Sproot()
        s.image = coast_images[ts][0]
        s.rect = s.image.get_frect(topleft = position)
        s.all_images = coast_images[ts]
        bg_sprites.append(s)
        animated_sprites.append(s)

    # get main objects
    objects = map.get_layer_by_name("Objects")
    for object in objects:
        position = (object.x, object.y)
        s = Sproot(object.image, object.image.get_frect(topleft = position))
        if object.name == "top":
            fg_sprites.append(s)
        else:
            main_sprites.append(s)
            collidable_sprites.append(s)

    # get monster patches
    objects = map.get_layer_by_name("Monsters")
    for object in objects:
        position = (object.x, object.y)
        s = Sproot(object.image, object.image.get_frect(topleft = position))
        s.kind = "monster_patch"
        main_sprites.append(s)

    # get player + other characters
    entities = map.get_layer_by_name("Entities")
    player_sprite = None
    for entity in entities:
        is_valid_entity = False
        if entity.name == "Player" and entity.properties["pos"] == player_start_pos:
            s = Sproot()
            player_sprite = s
            path = os.path.join("..", "graphics", "characters", PLAYER_FILE)
            images = load_all_images(path, 4, 4)
            is_valid_entity = True
        
        elif entity.name == "Professor":
            s = Sproot()
            prof_sprite = s
            path = os.path.join("..", "graphics", "characters", PROFESSOR_FILE)
            images = load_all_images(path, 4, 4)
            is_valid_entity = True
            s.active = True
            collidable_sprites.append(s)

        elif entity.name == "Character":
            s = Sproot()
            name = entity.properties["graphic"]
            path = os.path.join("..", "graphics", "nomekop", f"{name}.png")
            images = load_all_images(path, 2, 4)
            is_valid_entity = True
            s.kind = name
            s.active = True
            nomekop_sprites.append(s)
            collidable_sprites.append(s)
        
        if is_valid_entity:
            position = (entity.x, entity.y)
            s.image = images[0]
            s.rect = s.image.get_frect(topleft = position)
            s.all_images = images
            s.direction = 0
            main_sprites.append(s)


    return bg_sprites, main_sprites, fg_sprites, animated_sprites, nomekop_sprites, collidable_sprites, player_sprite, prof_sprite

def run_game():

    pg.init()
    screen = pg.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
    pg.display.set_caption("Nomékop")
    clock = pg.time.Clock()
    map_names = ["world.tmx"]
    super_secret = "SNEAKYSNAKEY"
    anti_venom_count = 0

    maps = import_maps(map_names)
    
    bg_sprites, main_sprites, fg_sprites, animated_sprites, nomekop_sprites, collidable_sprites, player_sprite, prof_sprite = setup_area(maps["world.tmx"], "house")
    frame = 0

    while True:
        
        time = clock.tick() / 1000
        # event loop
        for event in pg.event.get():
            if event.type == pg.QUIT:
                 pg.quit()
                 sys.exit()

        keys = pg.key.get_pressed()
        input_vector = vector()
        frame += ANIMATION_SPEED * time
        frame_index = int(frame % 4)

        # player movement
        if keys[pg.K_DOWN]:
            input_vector.y += 1
            player_sprite.direction = "down"
            player_sprite.image = player_sprite.all_images[0*4 + frame_index]

        elif keys[pg.K_LEFT]:
            input_vector.x -= 1 
            player_sprite.direction = "left"
            player_sprite.image = player_sprite.all_images[1*4 + frame_index]

        elif keys[pg.K_RIGHT]:
            input_vector.x += 1
            player_sprite.direction = "right"
            player_sprite.image = player_sprite.all_images[2*4 + frame_index]

        elif keys[pg.K_UP]:
            input_vector.y -= 1
            player_sprite.direction = "up"
            player_sprite.image = player_sprite.all_images[3*4 + frame_index]

        if not player_is_blocked_by_object(player_sprite, collidable_sprites):
            player_sprite.rect.center += time * input_vector * WALKING_SPEED

        # drawing logic
        screen.fill("black")
        offset = vector()
        offset.x = -(player_sprite.rect.center[0] - WINDOW_WIDTH/2)
        offset.y = -(player_sprite.rect.center[1] - WINDOW_HEIGHT/2)

        for i in range(len(animated_sprites)):
            animated_sprites[i].image = animated_sprites[i].all_images[0*4 + frame_index]
        
        # aggresive nomekop behavior
        i = 0
        while i < len(nomekop_sprites):
            s = nomekop_sprites[i]
            kind = s.kind
            nomekop_x, nomekop_y = s.rect.center
            player_x, player_y = player_sprite.rect.center

            if player_is_near_aggressive_nomekop(nomekop_x, nomekop_y, player_x, player_y, kind) and s.active:
                nomekop_sprites[i].image = nomekop_sprites[i].all_images[1*4 + frame_index]

                if kind == "Atrox" and player_is_behind_snake(nomekop_x, nomekop_y, player_x, player_y, player_sprite.direction) and keys[pg.K_SPACE] and s.active:
                    s.active = False
                    print("Collected anti-venom!")
                    anti_venom_count += 1
            else:
                nomekop_sprites[i].image = nomekop_sprites[i].all_images[0*4 + frame_index]
            i += 1

        # check for win condition when talking to professor herb
        if (vector(player_sprite.rect.center)-vector(prof_sprite.rect.center)).length() < 150 and player_sprite.direction == "up" and keys[pg.K_SPACE] and prof_sprite.active and anti_venom_count >= 2:
            seq = "ACCATGAGTAATGGGGCCAAAATGAGTAATGCCAAAGGGCCC"
            protein = translate_snake_dna(seq)
            if protein == super_secret:
                prof_sprite.active = False
                print(f"{protein}. Yes, of course, that it's it! We have the anti-venom!")
                audio_path = os.path.join("..", "data", "audio", "victory.wav")
                victory = pg.mixer.Sound(audio_path)
                victory.play()
            else:
                print(f"{protein}... hmmm not quite")


        for sprite in bg_sprites + sorted(main_sprites, key=return_y) + fg_sprites:
            screen.blit(sprite.image, sprite.rect.topleft + offset)

        pg.display.update()

if __name__ == "__main__":
    run_game()