import text, time, sys, random, math, threading

from os import system

RUNNING = True

STAR = ["."]
BULLET = ["=-"]
EBULLET = ["-="]


ENEMYL = ["  /|",
          " /| ",
          "/|  ",
          "\|  ",
          " \| ",
          "  \|"]
ENEMYM = [
         " /|",
         "/| ",
         "\| ",
         " \|"]
ENEMYS = ["/|",
          "\|"]



PLAYER = [
          "|\\= ",
          "----",
          "|/= "]

DEBRIS = [["/"],
        ["\\"],
        ["."],
        ["|"],
        ["["],
        ["]"],
        ["x"]]

GAME_STATE = "MENU"


global speed, lastScan, scanner
speed = 0
lastScan = time.time()
scanner = 0

def speedScanner():
    global speed, lastScan, scanner
    while True:
        if scanner > 170:
            speed = time.time() - lastScan
            lastScan = time.time()
            scanner = 0


threading1 = threading.Thread(target=speedScanner)
threading1.daemon = True
threading1.start()
frameclock = text.Frameclock()

screen = text.Screen(170,49)
logger = text.KeyLogger(screen)
player = text.Sprite(6, int(screen.height / 2), PLAYER, "player")

global objects, health, max_health, shoot_type, score, flash
shoot_type = 0
score = 0

max_health = 40
health = 40
objects = []

flash = False


class ObjectFactory:
    def makeStar():
        star = text.Sprite(170, random.randint(2, 47), STAR, "star")
        star.update = Update.star
        star.velocity = [0]
        star.velocity[0] = random.randint(-3, -1)
        objects.append(star)
    def makeBullet():
        global shoot_type
        if (shoot_type == 0):
            bullet = text.Sprite(player .x, player.y, BULLET, "bullet")
            bullet.update = Update.bullet
            objects.append(bullet)

            bullet2 = text.Sprite(player.x, player.y + 2, BULLET, "bullet")
            bullet2.update = Update.bullet
            objects.append(bullet2)

        elif shoot_type == 1:
            bullet = text.Sprite(player.x, player.y + 1, BULLET, "bullet")
            bullet.update = Update.bullet
            objects.append(bullet)

    def makeEBullet(enemy):
        bullet = text.Sprite(enemy.x, enemy.y + 1, EBULLET, "ebullet")
        bullet.update = Update.ebullet
        objects.append(bullet)
    def makeEnemy(t=-1):
        if (t == -1):
            t = random.randint(0, 10)
        if t < 4:
            enemy = text.Sprite(170, random.randint(2, 40), ENEMYM, "enemy")
            enemy.velocity = [-2]
            enemy.update = Update.enemy
            objects.append(enemy)
        elif t < 7:
            enemy = text.Sprite(170, random.randint(2, 40), ENEMYS, "enemy")
            enemy.velocity = [-4]
            enemy.update = Update.enemy
            objects.append(enemy)
        else:
            enemy = text.Sprite(170, random.randint(12, 30), ENEMYL, "enemy")
            enemy.velocity = [170, random.randint(12, 30)]
            enemy.update = Update.enemyADV
            objects.append(enemy)
    def makeExplosion(sprite):
        for i in range(0, random.randint(0, 10)):
            p = text.Sprite(sprite.x + int(sprite.width / 2), sprite.y +  int(sprite.height / 2), DEBRIS[random.randint(0, len(DEBRIS) - 1)], "debris")
            p.velocity = [random.randint(-1.0, 1.0), random.randint(-1.0, 1.0)]
            p.update = Update.debris
            p.life = random.randint(0, 20)
            objects.append(p)

class Update:
    def star(star):
        star.move(int(star.velocity[0]), 0)
        if star.x < 1:
            star.remove()

    def debris(debris):
        debris.move(int(debris.velocity[0]) - 2, int(debris.velocity[1]))
        debris.life -= 1

        # if debris.velocity[0] < 0:
        #     debris.velocity[0] += 0.01
        # elif debris.velocity[0] > 0:
        #     debris.velocity[0] -= 0.01
        #
        # if debris.velocity[1] < 0:
        #     debris.velocity[1] += 0.01
        # elif debris.velocity[1] > 0:
        #     debris.velocity[1] -= 0.01

        if debris.x < 1 or debris.life < 0:
            debris.remove()

    def bullet(bullet):
        global score
        for i in range(0, 4):
            bullet.move(1, 0)
            for o in objects:

                if o.name == "enemy" and o.rect.hasPoint(bullet.x, bullet.y):
                    o.remove()
                    bullet.remove()
                    ObjectFactory.makeExplosion(o)
                    score += 1000
                    break
            if bullet.x > 170:
                bullet.remove()
    def enemy(enemy):
        global health, score, flash
        enemy.move(int(enemy.velocity[0]), 0)
        if random.randint(0, 20) == 0:
            ObjectFactory.makeEBullet(enemy)

        if enemy.rect.hasPoint(player.rect.x + 3, player.rect.y+ 1):
            health -= 5
            flash = True
            enemy.remove()
            score += 100
            ObjectFactory.makeExplosion(enemy)


        if enemy.x < 1:
            enemy.remove()
    def ebullet(b):
        global health, flash
        for i in range(0, 6):
            b.move(-1, 0)


            if player.rect.hasPoint(b.rect.x, b.rect.y):
                health -= 1

                b.remove()
                ObjectFactory.makeExplosion(b)
                break

            if b.x < 1:
                b.remove()
    def enemyADV(enemy):
        global health, score, flash
        enemy.y = enemy.velocity[1] + int( math.sin(enemy.x / 8) * 6)

        enemy.move(-3, 0)
        enemy.rect = text.Rect(enemy.x, enemy.y, len(enemy.image[0]), len(enemy.image))

        if random.randint(0, 2) == 0:
            ObjectFactory.makeEBullet(enemy)

        if enemy.rect.hasPoint(player.rect.x + 3, player.rect.y+ 1):
            health -= 10
            flash = True
            score += 200
            enemy.remove()
            ObjectFactory.makeExplosion(enemy)

        if enemy.x < 1:
            enemy.remove()


def listener(key):
    global RUNNING, GAME_STATE, health, score
    if (key == "q"):
        RUNNING = False
    if GAME_STATE == "GAME":
        if (key == "s"):
            if player.y + player.height < screen.height - 1:
                player.move(0, 1)
        if (key == " "):
            ObjectFactory.makeBullet()
        if (key == "w"):
            if player.y > 1:
                player.move(0, -1)
    if GAME_STATE == "MENU" or GAME_STATE == "FAIL":
        if (key == " "):
            GAME_STATE = "GAME"
            health = max_health
            score = 0
            for i in range(len(objects) - 1, - 1, - 1):
               object = objects[i]
               if not object.name == "star":
                   del objects[i]

logger.addListener(listener)


while RUNNING:

    if (frameclock.skip < 0):
        scanner += 1
        screen.clear(" ")

        if GAME_STATE == "GAME":

            screen.draw.sprite(player)

            if random.randint(0, 2) == 0:
                ObjectFactory.makeStar()
            if random.randint(0, 20) == 0:
                ObjectFactory.makeEnemy()

            for i in range(len(objects) - 1, - 1, - 1):
                object = objects[i]
                object.update(object)
                if object.delete:
                    del objects[i]
                screen.draw.sprite(object)

            screen.draw.frame(text.Rect(screen.width - (max_health + 4), 0, max_health + 4, 6))
            scoreStr = (10 - len(str(score))) * "0" + str(score)
            screen.draw.text((screen.width - max_health - 2), 1, scoreStr)
            screen.draw.text((screen.width - max_health - 2), 3, "HEALTH")
            screen.draw.text(screen.width - max_health - 2, 4, "▓" * health)

            if flash:
                screen.clear(".")

            if health < 0:
                GAME_STATE = "FAIL"
        elif GAME_STATE == "MENU":
            screen.clear(" ")
            screen.draw.text(int(screen.width / 2) - 10, int(screen.height / 2), "PRESS SPACE TO PLAY");
        elif GAME_STATE == "FAIL":
            screen.clear(" ")
            screen.draw.text(int(screen.width / 2) - 10, int(screen.height / 2), "PRESS SPACE TO REPLAY");
            screen.draw.text(int(screen.width / 2) - 10, int(screen.height / 2) - 4, "YOU SCORED " + str(score));
        screen.draw.frame(screen.rect)
        # screen.draw.text(0, 0, str(frameclock.getFPS()) + "fps")

    screen.draw.text(0, 0, str(frameclock.getFPS()) + "fps")
    if flash:
        screen.refresh(color=text.RED)
    else:
        screen.refresh()

    if flash:
        flash = False
    frameclock.tick(30)

sys.exit()
