import pygame,math,random
from pygame.math import Vector2
from game.ui import Effect

def snaptogrid(c):
    coords = math.floor(c[0]/48), math.floor(c[1]/48)
    coords = (coords[0]*48)+24, (coords[1]*48)+24
    return coords

#rate, radius, dmg
props = {"gs":[1000, 312, 1], "gds":[1000, 312, 2], "grs":[100, 288, 0.33], "gcs":[1700, 350, 5], "gss":[5000, 684, 10],
         "ws":[667, 312, 1], "wds":[740, 312, 1.75], "wrs":[75, 288, 0.33], "wcs":[1200, 350, 4], "wss":[4250, 684, 8],
         "fs":[1000, 312, 2], "fds":[1100, 336, 4], "frs":[115, 300, 0.75], "fcs":[1300, 350, 8], "fss":[5250, 700, 15]}

bulletimages = {}
towerimages = {}
for img in props.keys():
    bulletimages[img] = pygame.image.load("./images/bullets/"+str(img)+".png")
    towerimages[img] = pygame.image.load("./images/towers/" + str(img) + ".png")

class Tower(pygame.sprite.Sprite):
    def __init__(self, type, pos):
        global towerimages
        pygame.sprite.Sprite.__init__(self)
        self.image = towerimages[str(type)]
        self.oimage = self.image
        self.oimage.set_alpha(255)
        self.image.set_alpha(255)
        self.rect = self.image.get_rect()
        self.rect.center = list(pos)
        self.type = str(type)
        self.baseprops = list(props[self.type])
        self.props = list(props[self.type])
        self.cooldown = 0
        self.rotation = 0
        self.orotation = 0
        self.target = None
        self.targettype = "close"
        self.kills = 0
        self.baseprofit = [8, 16]
        self.profit = [8, 16]
        if self.type.endswith("s"):
            r = props[self.type][1]
            self.rangesurface = pygame.surface.Surface([r,r])
            self.rangesurface = self.rangesurface.get_rect()
            self.rangesurface.center = self.rect.center
    def ReRange(self):
        r = self.props[1]
        self.rangesurface = pygame.surface.Surface([r, r])
        self.rangesurface = self.rangesurface.get_rect()
        self.rangesurface.center = self.rect.center
    def update(self, pa, mouse, clock, enemies, bulletgrp, fields, sounds, sfx, getboost=None):
        if getboost != None:
            if getboost[0] == "damage":
                self.props[2] = list(self.props)[2]*list(getboost)[1]
            elif getboost[0] == "range":
                self.props[1] = list(self.props)[1] * list(getboost)[1]
                self.ReRange()
            elif getboost[0] == "firerate":
                self.props[0] = list(self.props)[0]/list(getboost)[1]
            elif getboost[0] == "profit":
                self.profit = [round(self.profit[0]*list(getboost)[1]), round(self.profit[1]*list(getboost)[1])]
        else:
            if snaptogrid(mouse) == self.rect.center:
                pa.highlightedtower = self
            if pygame.sprite.spritecollide(self, fields, False):
                field = pygame.sprite.spritecollide(self, fields, False)[0]
                for r in field.requirements.keys():
                    if r in ["w", "g", "f"] and self.type.startswith(r): #Color
                        field.requirements[r] -= 1
                    if r in ["ds", "rs", "cs", "ss", "s"] and self.type.endswith(r): #Type
                        if r == "s":
                            da = True
                            for i in ["ds", "rs", "cs", "ss"]:
                                if self.type.endswith(i):
                                    da = False
                                    break
                            if da:
                                field.requirements[r] -= 1
                        else:
                            field.requirements[r] -= 1
                    elif r == "a": #Any Tower
                        field.requirements[r] -= 1
            if self.target != None:
                if not self.target.alive():
                    self.target = None
                elif not self.rangesurface.colliderect(self.target.rect):
                    self.target = None
            if self.cooldown <= 0:
                self.cooldown = self.props[0]
                if self.type.endswith("s") and self.target != None:
                    if self.type.endswith("ss"):
                        velocity = Vector2(self.target.rect.centerx - self.rect.centerx,
                                           self.target.rect.centery - self.rect.centery).normalize() * clock.get_fps() * 0.4
                    else:
                        velocity = Vector2(self.target.rect.centerx - self.rect.centerx,
                                           self.target.rect.centery - self.rect.centery).normalize() * clock.get_fps() * 0.2
                    b = Bullet(self.type, self.rect.center, velocity, self.rotation, self.rangesurface, self)
                    bulletgrp.add(b)
                    sfx.play(sounds["shoot"])
            else:
                self.cooldown -= clock.get_time()
            if self.target == None:
                self.oldrect = self.rect
                self.rect = self.rangesurface
                self.rect.center = self.oldrect.center
                inrange = pygame.sprite.spritecollide(self, enemies, False)
                self.rect = self.oldrect
                self.rect.center = self.oldrect.center
                if len(inrange) > 0:
                    if self.targettype == "close":
                        distances = []
                        for i in inrange:
                            distances.append(math.sqrt(abs((i.rect.centerx - self.rect.centerx)^2 + (i.rect.centery - self.rect.centery)^2)))
                        closest = min(distances)
                        closest_index = distances.index(closest)
                        self.target = inrange[closest_index]
                    elif self.targettype == "strong":
                        strengths = []
                        for i in inrange:
                            strengths.append((i.health))
                        strongest = max(strengths)
                        strongest_index = strengths.index(strongest)
                        self.target = inrange[strongest_index]
            elif self.target != None:
                try:
                    self.rotation = math.atan(abs(self.target.rect.centery - self.rect.centery) / abs(
                        self.target.rect.centerx - self.rect.centerx)) * 57.2958
                    self.rotation = math.round(self.rotation)
                except:
                    pass
                self.orotation = self.rotation
                if (self.target.rect.centerx < self.rect.centerx and self.target.rect.centery < self.rect.centery):
                    self.rotation = -self.orotation
                if (self.target.rect.centerx < self.rect.centerx and self.target.rect.centery < self.rect.centery):
                    self.rotation = -self.orotation + 180
                if (self.target.rect.centerx < self.rect.centerx and self.target.rect.centery > self.rect.centery):
                    self.rotation = self.orotation + 180
                if (self.target.rect.centerx > self.rect.centerx and self.target.rect.centery > self.rect.centery):
                    self.rotation = -self.orotation
                self.image = pygame.transform.rotate(self.oimage, round(self.rotation))
                oldcenter = self.rect.center
                self.rect = self.image.get_rect()
                self.rect.center = oldcenter
            self.props = list(self.baseprops)
            self.profit = [8, 16]
            self.ReRange()

class Bullet(pygame.sprite.Sprite):
    def __init__(self, type, pos, velocity, rotation, rangesurface, parent):
        global bulletimages
        pygame.sprite.Sprite.__init__(self)
        self.oimage = bulletimages[str(type)]
        self.velocity = velocity
        self.rotation = rotation
        self.type = str(type)
        self.image = pygame.transform.rotate(self.oimage, round(rotation)+90)
        self.rect = self.image.get_rect()
        self.rect.center = pos
        self.damage = props[self.type][2]
        self.pos = Vector2(self.rect.centerx, self.rect.centery)
        self.mask = pygame.mask.from_surface(self.image)
        self.rs = rangesurface
        self.parent = parent
        self.hit = False
    def update(self, enemies, pa, sounds, sfx):
        if not self.parent.alive():
            self.kill()
        self.pos += self.velocity
        self.rect.center = [self.pos.x, self.pos.y]
        c = pygame.sprite.spritecollide(self, enemies, False)
        if c:
            s = c[0]
            s.mask = pygame.mask.from_surface(s.image)
            if pygame.sprite.collide_mask(self, s) and not self.hit:
                s.health -= self.damage
                self.hit = True
                if s.health <= 0:
                    sfx.play(sounds["kill"])
                    s.kill()
                    pa.addcash += round((0.1*random.randint(self.parent.profit[0], self.parent.profit[1]))*(s.basehealth))
                    self.parent.kills += 1
                self.kill()
        if not self.rect.colliderect(self.rs):
            self.kill()
        if self.rect.left > 1296 or self.rect.right < 0:
            self.kill()
        if self.rect.top > 960 or self.rect.bottom < 0:
            self.kill()
