from django.db import models

from channels.generic.websocket import WebsocketConsumer

from games.models import GameModel

import json

from transcendence.abstract.AbstractRoomMember import AbstractRoomMember
from transcendence.abstract.AbstractRoom import AbstractRoom
from transcendence.abstract.AbstractRoomManager import AbstractRoomManager

# Create your models here.tu
class TournamentModel(models.Model):

	name = models.CharField(max_length = 100)
	nb_players = models.IntegerField()
	nb_players_by_game = models.IntegerField()
	level = models.IntegerField()
	started = models.BooleanField(default = False)
	finished = models.BooleanField(default = False)

	def create_game(self, level, players_id):
		game_id = GameModel().create(players_id = players_id)
		TournamentGamesModel(game_id = game_id, tournament_id = self.pk, tournament_level = level).save()
		return game_id
	
	def get_games_id_by_level(self, level):
		tmp = TournamentGamesModel.objects.filter(tournament_id = self.pk, tournament_level = level)
		return [instance.game_id for instance in tmp]

	def get_games_id(self):
		return [tournament_game.game_id for tournament_game in TournamentGamesModel.objects.filter(tournament_id = self.pk)]
	
	def get_players_id(self):
		return [model.participant_id for model in TournamentParticipantsModel.objects.filter(tournament_id=self.pk)]
	
	def is_a_participant(self, participant_id: int):
		return TournamentParticipantsModel.objects.filter(participant_id = participant_id, tournament_id = self.pk).exists()

	def add_participants(self, participants_id: [int]):
		for participant_id in participants_id:
			TournamentParticipantsModel(tournament_id = self.pk, participant_id = participant_id).save()

	def start(self, participants_id: [int]):
		self.started = True
		self.add_participants(participants_id)
		games_id = [int]
		for i in range(0, len(participants_id), self.nb_players_by_game):
			game_id = self.create_game(0, participants_id[i : i + self.nb_players_by_game])
			games_id.append(game_id)
		self.save()
		return games_id

class TournamentParticipantsModel(models.Model):
	tournament_id = models.IntegerField()
	participant_id = models.IntegerField()

class TournamentGamesModel(models.Model):

	tournament_id = models.IntegerField()
	tournament_level = models.IntegerField()
	game_id = models.IntegerField()

class TournamentMember(AbstractRoomMember):

	def __init__(self, user_id: int, socket: WebsocketConsumer, room):
		super().__init__(user_id, socket)
		self.participate = False
		self.room = room

	def receive(self, text_data: str = None, byte_dates: bytes = None):
		
		if (text_data is None):
			return

		data: dict = json.loads(text_data)

		if (data.get("participate") is not None):
			self.room.update_participants(self)

	def send_error_message(self, message: str):
		self.send("error", {"error_message": message})

	def go_to(self, url: str):
		self.send("go_to", {"url": url})
	
	def send_participating(self):
		self.send("is_participant", {"is_participant": self.participate})

class TournamentRoom(AbstractRoom):

	def __init__(self, room_manager, tournament_id: int):
		super().__init__(room_manager)
		self.tournament_id = tournament_id
		self.tournament = TournamentModel.objects.get(pk = tournament_id)

	def start(self):
		self.broadcast("tournament_start")
		games_id = self.tournament.start(self.get_participants_id())
		for i, participant in enumerate(self.get_participants()):
			participant: TournamentMember
			participant.go_to(f"games/{games_id[i // self.tournament.nb_players_by_game]}")

	def update_participants(self, member: TournamentMember):
		if (self.tournament.started):
			member.send_error_message("Tournament already started")
			return
		member.participate = not member.participate
		nb_participants = self.get_nb_participants()
		self.broadcast("update_participants", {"nb_participants": nb_participants})
		member.send_participating()
		if (nb_participants == self.tournament.nb_players):
			self.start()

	def get_nb_participants(self):
		if (self.tournament.started):
			return self.tournament.nb_players
		nb_participants = 0
		for member in self._member_list:
			member: TournamentMember
			if (member.participate):
				nb_participants += 1
		return nb_participants 

	def get_participants(self):
		return [member for member in self._member_list if member.participate]

	def get_participants_id(self):
		return [member.user_id for member in self._member_list if member.participate]

	def append(self, member: TournamentMember):
		super().append(member)
		if self.tournament.started:
			member.participate = self.tournament.is_a_participant(member.user_id)
		member.send_participating()
		member.send("nb_participants", {"nb_participants": self.get_nb_participants()})

class TournamentRoomManager(AbstractRoomManager):

	def get(self, tournament_id: int):

		for room in self._room_list:
			if (room.tournament_id == tournament_id):
				return room
		
		if (TournamentModel.objects.filter(pk = tournament_id).exists()):
			room = TournamentRoom(self, tournament_id)
			self.append(room)
			return room
		
		return None

tournament_manager: TournamentRoomManager = TournamentRoomManager()