# -*- coding: utf-8 -*-


from collections import namedtuple
import random

import api
from api import erreur


def is_ennemy_turret(c):
    return (game.info_case(c) == api.case_info.CASE_TOURELLE and
            game.tourelle_case(c).joueur in api.adversaires())

def ennemy_turrets(c, radius):
    """Coordonnees des tourelles ennemies dans le cercle de centre c."""
    return filter(is_ennemy_turret, circle(c, radius))

def prochaine_etape(a, b, tourelle=0):
    """tourelle=1 si b est tourelle, 0 sinon."""
    c = chemin(a, b)
    etape = c[min(api.PORTEE_SORCIER-1, len(c)-1-tourelle)]
    return etape

def children(c):
    a = ((c[0]-1, c[1]), (c[0], c[1]+1),
         (c[0]+1, c[1]), (c[0], c[1]-1))
    a = list(filter(lambda b: 0<=b[0]<31 and 0<=b[1]<31, a))
    random.shuffle(a)
    return a

def walkable_children(c):
    return list(filter(lambda b: not is_ennemy_turret(b),
                       children(c)))

def chemin(a, b):
    visited = set()
    q = [(a, ())]

    for v, p in q:
        if v == b:
            return p+(v,)
        for v2 in walkable_children(v):
            if not v2 in visited:
                visited.add(v2)
                q.append((v2, p+(v,)))


def circle(center, radius):
    dists = {center:0}
    q = [center]
    for v in q:
        if dists[v] == radius:
            return tuple(dists.keys())
        for v2 in children(v):
            if not v2 in dists:
                dists[v2] = dists[v] + 1
                q.append(v2)


class Bataillon():
    def __init__(self, n, cible, armee):
        self.n = n
        self.effectif = 0
        self.cible = cible
        self.pos = None
        self.armee = armee

    def fixe_cible(self, cible):
        self.cible = cible
        #self.armee.bataillons_a_deplacer.append(self)

    def creer(self):
        if self.effectif < self.n:
            n = min(self.n - self.effectif, moi.magie()//api.COUT_SORCIER)
            moi.creer(n)
            self.effectif += n
        else:
            self.pos = (0,0)
            self.armee.bataillon_cree(self)


    def deplacer(self):
        self.n = min(self.n, moi.nb_sorciers(self.pos))
        arrivee = prochaine_etape(self.pos, self.cible)
        err = moi.deplacer(self.pos, arrivee, self.n)
        #print(err)
        self.pos = arrivee
        if self.pos == self.cible:
            pass
            #self.armee.bataillon_arrive(self)


class Armee():
    def __init__(self):
        self.bataillons = []
        self.bataillons_a_creer = []
        self.bataillons_a_deplacer = []


    def update_construction(self):
        for bat in self.bataillons_a_creer:
            bat.creer()

    def update_deplacement(self):
        for bat in self.bataillons_a_deplacer:
            bat.deplacer()

    def bataillon_arrive(self, bat):
        self.bataillons_a_deplacer.remove(bat)

    def bataillon_cree(self, bat):
        self.bataillons_a_creer.remove(bat)
        self.bataillons_a_deplacer.append(bat)

    def add(self, n, cible):
        bat = Bataillon(n, cible, self)
        self.bataillons.append(bat)
        self.bataillons_a_creer.append(bat)


def _(x, y):
    """Transforme absolu en relatif et inversement."""
    if moi.base[0] == api.TAILLE_TERRAIN - 1:
        x = api.TAILLE_TERRAIN - 1 - x
    if moi.base[1] == api.TAILLE_TERRAIN - 1:
        y = api.TAILLE_TERRAIN - 1 - y
    return x, y


def dist(a, b):
    return abs(b[0] - a[0]) + abs(b[1] - a[1])


class Game():
    def __init__(self):
        self.data = []
        self.sorciers = []

    def update(self):
        self.data = []
        self.sorciers = []
        for x in range(api.TAILLE_TERRAIN):
            self.data[x] = []
            self.sorciers[x] = []
            for y in range(api.TAILLE_TERRAIN):
                self.data[x][y] = game.info_case((x,y))
                self.sorciers[x][y] = sum((adv.nb_sorciers((x,y)) for adv in adversaires))

    def info_case(self, c):
        return api.info_case(_(*c))

    def joueur_case(self, c):
        return api.joueur_case(_(*c))

    def tourelle_case(self, c):
        return api.tourelle_case(_(*c))

    def chemin(self, a, b):
        return [_(*c) for c in api.chemin(_(*a), _(*b))]


class Joueur():
    def __init__(self, id_):
        self.id_ = id_
        self.base = api.base_joueur(id_)

    def nb_sorciers(self, c):
        return api.nb_sorciers(_(*c), self.id_)

    def nb_sorciers_deplacable(self, c):
        return api.nb_sorciers_deplacable(_(*c), self.id_)

    def constructible(self, c):
        return api.constructible(_(*c), self.id_)

    def tourelles_joueur(self):
        a = api.tourelles_joueur(self.id_)
        return [_(*c.pos) for c in a]

    def base_joueur(self):
        return _(*api.base_joueur(self.id_))

    def magie(self):
        return api.magie(self.id_)

    def constructible(self, c):
        return api.constructible(_(*c), self.id_)


class Moi(Joueur):
    def __init__(self):
        super().__init__(api.moi())

    def construire(self, c, portee):
        return api.construire(_(*c), portee)

    def supprimer(self, c):
        return api.detruire(_(*c))

    def tirer(self, pts, a, b):
        return api.tirer(pts, _(*a), _(*b))

    def creer(self, n):
        return api.creer(n)

    def deplacer(self, a, b, n):
        return api.deplacer(_(*a), _(*b), n)

    def assieger(self, a, b, n):
        return api.assieger(_(*a), _(*b), n)

moi = Moi()
game = Game()
adversaires = [Joueur(id_) for id_ in api.adversaires()]