import pygame as pg
from settings import *
from random import choice, randrange
vec = pg.math.Vector2


class Spritesheet:
    # utility class for loading and parsing spritesheets
    def __init__(self,filename):
        self.spritesheet = pg.image.load(spritesheet).convert()
        
    def get_image(self, x, y, width, height):
        # grab an image out of a larger spritesheet
        image = pg.Surface((width,height))
        image.blit(self.spritesheet,(0,0), (x, y, width, height))
        image = pg.transform.scale(image,(width//2,height//2))
        return image
        

class Player(pg.sprite.Sprite):
    def __init__(self, game):
        self._layer = player_layer
        self.groups = game.all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.walking = False
        self.jumping = False
        self.current_frame = 0
        self.last_update = 0
        self.load_images()
        self.image = self.standing_frames[0]
        self.rect = self.image.get_rect()
        self.rect.center = (40,height -100)
        self.pos = vec(40,height - 150)
        self.vel = vec(0, 0)
        self.acc = vec(0, 0)

    def load_images(self):
        self.standing_frames = [self.game.spritesheet.get_image(614,1063,120, 191),
                               self.game.spritesheet.get_image(690,406,120,201)]
        for frame in self.standing_frames:
            frame.set_colorkey(black)
        self.walk_frames_r = [self.game.spritesheet.get_image(678,860,120,201),
                              self.game.spritesheet.get_image(692,1458,120,207)]
        for frame in self.walk_frames_r:
            frame.set_colorkey(black)
        self.walk_frames_l = []
        for frame in self.walk_frames_r:
            frame.set_colorkey(black)
        for frame in self.walk_frames_r:
            self.walk_frames_l.append(pg.transform.flip(frame, True, False))
            self.jump_frame = self.game.spritesheet.get_image(416,1660,150,181)
            self.jump_frame.set_colorkey(black)

    def jump_cut(self):
        if self.jumping:
            if self.vel.y < -3:
                self.vel.y = -3

    def jump(self):
        # Jump only if standing platform
        self.rect.x +=2
        hits = pg.sprite.spritecollide(self, self.game.platforms,False)
        self.rect.x -= 2
        if hits and not self.jumping:
            self.game.jump_sound.play()

            self.jumping  = True
            self.vel.y = -player_jump
        
    def update(self):
        self.animate()
        self.acc = vec(0, player_grav)
        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT]:
            self.acc.x = -player_acc
        if keys[pg.K_RIGHT]:
            self.acc.x = player_acc

        # apply friction
        self.acc.x += self.vel.x * player_friction
        # equations of motion
        self.vel += self.acc
        if abs(self.vel.x) < 0.1:
            self.vel.x = 0
        self.pos += self.vel + 0.5 * self.acc
        
        # wrap around the side of the screen
        if self.pos.x > width + self.rect.width:
            self.pos.x = 0 - self.rect.width/2
        if self.pos.x < 0 - self.rect.width/2:
            self.pos.x = width + self.rect.width/2
            
        self.rect.midbottom = self.pos

    def animate(self):
        now = pg.time.get_ticks()
        if self.vel.x != 0:
            self.walking = True
        else:
            self.walking = False

        if self.walking:
            if now - self.last_update > 200:
                self.last_update = now
                self.current_frame = (self.current_frame + 1)% len(self.walk_frames_l)
                bottom = self.rect.bottom
                if self.vel.x > 0:
                    self.image = self.walk_frames_r[self.current_frame]
                else:
                    self.image = self.walk_frames_l[self.current_frame]
                self.rect = self.image.get_rect()
                self.rect.bottom = bottom
                
        # show idle animation
        if not self.jumping and not self.walking:
            if now - self.last_update > 250:
                self.last_update = now
                self.current_frame = (self.current_frame + 1)% len(self.standing_frames)
                bottom = self.rect.bottom
                self.image = self.standing_frames[self.current_frame]
                self.rect = self.image.get_rect()
                self.rect.bottom = bottom
        self.mask =  pg.mask.from_surface(self.image)
class Cloud(pg.sprite.Sprite):
    def __init__(self, game):
        self._layer = cloud_layer
        self.groups = game.all_sprites, game.clouds
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = self.game.spritesheet.get_image(0,1152,260,134)
        self.image.set_colorkey(black)
        self.rect = self.image.get_rect()
        scale = randrange(50,100)/100
        self.image = pg.transform.scale(self.image,(int(self.rect.width * scale),int(self.rect.height * scale)))
        self.rect.x = randrange(width - self.rect.width)
        self.rect.y = randrange(-500,-50)

    def update(self):
       if self.rect.top > height*2:
            self.kill()
        
class Platform(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self._layer = platform_layer
        self.groups = game.all_sprites, game.platforms
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game  = game
        images = [self.game.spritesheet.get_image(0,288,380,94),
                self.game.spritesheet.get_image(213,1662,201,100)
                 ]
        self.image = choice(images)
        self.image.set_colorkey(black)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        if randrange(100) < pow_spawn_pct:
            Pow(self.game, self)
        if randrange(5) < coin_spawn_pct:
            Coins(self.game, self)
    


class Pow(pg.sprite.Sprite):
    def __init__(self, game, plat):
        self._layer = powerup_layer
        self.groups = game.all_sprites,game.powerups
        pg.sprite.Sprite.__init__(self,self.groups)
        self.game  = game
        self.plat = plat
        self.type  = choice(["boost"])
        self.image = self.game.spritesheet.get_image(820,1805,71,70)
        self.image.set_colorkey(black)
        self.rect = self.image.get_rect()
        self.rect.centerx = self.plat.rect.centerx
        self.rect.bottom = self.plat.rect.top -5

    def update(self):
        self.rect.bottom = self.plat.rect.top -5
        if not self.game.platforms.has(self.plat):
            self.kill()
            
class Mob(pg.sprite.Sprite):
    def __init__(self, game):
        self._layer = mob_layer
        self.groups = game.all_sprites,game.mobs
        pg.sprite.Sprite.__init__(self,self.groups)
        self.game  = game
        self.image_up = self.game.spritesheet.get_image(566,510,122,139)
        self.image_up.set_colorkey(black)
        self.image_down = self.game.spritesheet.get_image(568,1534,122,135)
        self.image_down.set_colorkey(black)
        self.image = self.image_up
        self.rect = self.image.get_rect()
        self.rect.centerx = choice([-100,width + 100])
        self.vx = randrange(1, 4)
        if self.rect.centerx > width:
            self.vx += -1
        self.rect.y = randrange(height/2)
        self.vy = 0
        self.dy = 0.5

    def update(self):
        self.rect.x += self.vx
        self.vy += self.dy
        if self.vy > 3 or self.vy < -3:
            self.dy *= -1
        center = self.rect.center
        if self.dy < 0:
            self.image = self.image_up
        else:
            self.image = self.image_down
        self.rect = self.image.get_rect()
        self.mask =  pg.mask.from_surface(self.image)
        self.rect.center = center
        self.rect.y += self.vy
        if self.rect.left > width +100 or self.rect.right < -100:
            self.kill()
            
class Coins(pg.sprite.Sprite):
    def __init__(self, game, plat):
        self._layer = coins_layer
        self.groups = game.all_sprites,game.coins
        pg.sprite.Sprite.__init__(self,self.groups)
        self.game  = game
        self.plat = plat
        self.type  = choice(["gold"])
        self.image =self.game.spritesheet.get_image(698,1931,84,84)
        self.image.set_colorkey(black)
        self.rect = self.image.get_rect()
        self.rect.centerx = self.plat.rect.centerx
        self.rect.bottom = self.plat.rect.top -5
       
    def update(self):
        self.rect.bottom = self.plat.rect.top -5
        if not self.game.platforms.has(self.plat):
            self.kill()
            
        
    
