using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Networking.Types;
using UnityEngine.Networking.Match;
using System;

public class Serveur : MonoBehaviour
{

	private const int MAX_USER = 100;
	private const int PORT = 26000;
	private const int WEB_PORT = 26001;
	private const int BYTE_SIZE = 1024;

	private byte reliableChannel;
	private int HostId;
	private int WebHostId;

	private bool isStarted;
	public byte error;

	private int Nombre_clients_connecte = 0;

	private bool client1_clicked = false;
	private bool client2_clicked = false;
	private bool client3_clicked = false;

	private bool entreevideoproduit = false;

	#region MonoBehaviour
	private void Start()
	{
		DontDestroyOnLoad(gameObject);
		Init();
	}
	private void Update()
	{
		UpdateMessagePump();
	}
	#endregion


	public void Init()
	{
		// Debug.Log("wesh");
		NetworkTransport.Init();

		ConnectionConfig cc = new ConnectionConfig();
		reliableChannel = cc.AddChannel(QosType.Reliable);

		HostTopology topo = new HostTopology(cc, MAX_USER);

		//Code concernant uniquement le serveur
		HostId = NetworkTransport.AddHost(topo, PORT, null);
		WebHostId = NetworkTransport.AddWebsocketHost(topo, WEB_PORT, null);

		Debug.Log(string.Format("Ouverture de connexion sur le port {0} et sur le webport {1}", PORT, WEB_PORT));
		isStarted = true;
	}

	public void Shutdown()
	{
		isStarted = false;
		NetworkTransport.Shutdown();
	}

	private void UpdateMessagePump()
	{
		if (!isStarted)
			return;

		int recHostId;
		int connectionID;
		int channelId;

		byte[] recBuffer = new byte[BYTE_SIZE];
		int dataSize;

		NetworkEventType type = NetworkTransport.Receive(out recHostId, out connectionID, out channelId, recBuffer, BYTE_SIZE, out dataSize, out error);
		switch (type)
		{
			case NetworkEventType.Nothing:
				break;

			case NetworkEventType.ConnectEvent:
				Debug.Log(string.Format("User {0} has connected par le host {1}", connectionID, recHostId));
				Nombre_clients_connecte += 1;
				Debug.Log(string.Format("Le nombnre de client connecté est maintenant de {0}", Nombre_clients_connecte));
				//Debug.Log(string.Format("heure de connexion : " + DateTimeOffset.Now.ToUnixTimeMilliseconds()));

				//vérification du nombre de clients connecté, si =3 alors on démarre l'experience sinon, on attend (break)
				if (Nombre_clients_connecte == 3)
				{
					//démarrage de l'experience
					Debug.Log("nombre de clients connecté = 2, démmarrage de l'experience");
					StartExperience(connectionID, recHostId);
				}
				break;

			case NetworkEventType.DisconnectEvent:
				Debug.Log(string.Format("User {0} has disconnected", connectionID));
				Nombre_clients_connecte += -1;
				Debug.Log(string.Format("Le nombnre de client connecté est maintenant de {0}", Nombre_clients_connecte));
				Deconnexionvoisin(connectionID, recHostId);
				break;

			case NetworkEventType.DataEvent:
				// Debug.Log(recBuffer[0]);
				BinaryFormatter formatter = new BinaryFormatter();
				MemoryStream ms = new MemoryStream(recBuffer);
				NetMsg msg = (NetMsg)formatter.Deserialize(ms);

				OnData(connectionID, channelId, recHostId, msg);
				break;

			default:
			case NetworkEventType.BroadcastEvent:
				Debug.Log("Unexcpected network event type");
				break;
		}
	}

	#region OnData
	private void OnData(int cnnId, int channelId, int recHostId, NetMsg msg)
	{
		Debug.Log("Message recu du type " + msg.OP);

		switch (msg.OP)
		{
			case NetOp.None:
				Debug.Log("UNEXPECTED NETOP");
				break;

			case NetOp.CreateAccount:
				CreateAccount(cnnId, channelId, recHostId, (Net_CreateAccount)msg);
				break;

			case NetOp.Notificationvoisin:
				Sortieveille(cnnId, recHostId);
				break;

			case NetOp.Videoproduit:
				entreevideoproduit = true;
				Sortieveille(cnnId, recHostId);
				break;

		}
	}

	//Fonction pour démarrer l'experience
	private void StartExperience(int cnnId, int recHostId)
	{
		Net_Lancementexperience le = new Net_Lancementexperience();
		//	long timestampdemarrage;

		//	timestampdemarrage = DateTimeOffset.Now.ToUnixTimeMilliseconds() + 3000;
		//	le.timestamp = timestampdemarrage;

		SendClient1(recHostId, cnnId, le);
		SendClient2(recHostId, cnnId, le);
		SendClient3(recHostId, cnnId, le);
	}


	private void CreateAccount(int cnnId, int channelId, int recHostId, Net_CreateAccount ca)
	{
		//Debug.Log(string.Format("{0},{1},{2}", ca.Username, ca.Password, ca.Email));
		Debug.Log(string.Format("Le Client {0} et id {1} est pret à démarrer", cnnId, recHostId));
		Debug.Log(string.Format("Le nom du Client est {0}", ca.Username));

		Nombre_clients_connecte += 1;
		Debug.Log(string.Format("Le nombnre de client connecté est maintenant de {0}", Nombre_clients_connecte));


		Net_OnCreateAccount oca = new Net_OnCreateAccount();
		oca.Success = 0;
		oca.Information = "C'est good pelo";

		SendClient(recHostId, cnnId, oca);
	}


	private void Sortieveille(int cnnId, int recHostId)
	{

		Debug.Log(string.Format("Le Client {0} et id {1} a envoyé un événement click", cnnId, recHostId));


		if (entreevideoproduit == true)
		{
			StopAllCoroutines();
			entreevideoproduit = false;
			StartCoroutine("start_compteur_veille_videoproduit");

			if (cnnId == 1 && client1_clicked == false && client2_clicked == false && client3_clicked == false)
			{
				Net_Sortieveille sv = new Net_Sortieveille();
				SendClient2(recHostId, cnnId, sv);
				SendClient3(recHostId, cnnId, sv);
				Debug.Log(string.Format("Envoi d'un message aux clients 2 et 3"));
				client1_clicked = true;
			}

			if (cnnId == 2 && client1_clicked == false && client2_clicked == false && client3_clicked == false)
			{
				Net_Sortieveille sv = new Net_Sortieveille();
				SendClient1(recHostId, cnnId, sv);
				SendClient3(recHostId, cnnId, sv);
				Debug.Log(string.Format("Envoi d'un message aux clients 1 et 3"));
				client2_clicked = true;
			}

			if (cnnId == 3 && client1_clicked == false && client2_clicked == false && client3_clicked == false)
			{
				Net_Sortieveille sv = new Net_Sortieveille();
				SendClient1(recHostId, cnnId, sv);
				SendClient2(recHostId, cnnId, sv);
				Debug.Log(string.Format("Envoi d'un message aux clients 1 et 2"));
				client3_clicked = true;
			}
		}


		else if (entreevideoproduit == false)
		{
			StopAllCoroutines();
			StartCoroutine("start_compteur_veille");

			if (cnnId == 1 && client1_clicked == false && client2_clicked == false && client3_clicked == false)
			{
				Net_Sortieveille sv = new Net_Sortieveille();
				SendClient2(recHostId, cnnId, sv);
				SendClient3(recHostId, cnnId, sv);
				Debug.Log(string.Format("Envoi d'un message aux clients 2 et 3"));
				client1_clicked = true;
			}

			if (cnnId == 2 && client1_clicked == false && client2_clicked == false && client3_clicked == false)
			{
				Net_Sortieveille sv = new Net_Sortieveille();
				SendClient1(recHostId, cnnId, sv);
				SendClient3(recHostId, cnnId, sv);
				Debug.Log(string.Format("Envoi d'un message aux clients 1 et 3"));
				client2_clicked = true;
			}

			if (cnnId == 3 && client1_clicked == false && client2_clicked == false && client3_clicked == false)
			{
				Net_Sortieveille sv = new Net_Sortieveille();
				SendClient1(recHostId, cnnId, sv);
				SendClient2(recHostId, cnnId, sv);
				Debug.Log(string.Format("Envoi d'un message aux clients 1 et 2"));
				client3_clicked = true;
			}
		}

	}


	private void Deconnexionvoisin(int cnnId, int recHostId)
	{
		Debug.Log("un voisin s'est deconnecté, envoi d'un message aux autres clients");
		Net_Deconnexionvoisin dv = new Net_Deconnexionvoisin();
		SendClient1(recHostId, cnnId, dv);
		SendClient2(recHostId, cnnId, dv);
		SendClient3(recHostId, cnnId, dv);
		StopCoroutine("start_compteur_veille");
	}

	private IEnumerator start_compteur_veille()
	{
		while (true)
		{
			Debug.Log("compteur démarré");
			yield return new WaitForSeconds(40); // on attend X secondes pour lancer l'animation de veille
			Debug.Log("compteur terminé");

			Net_Lancementexperience le = new Net_Lancementexperience();

			SendClient1(0, 1, le);
			SendClient2(1, 2, le);
			SendClient3(2, 3, le);

			client1_clicked = false;
			client2_clicked = false;
			client3_clicked = false;
			break;
		}
	}


	private IEnumerator start_compteur_veille_videoproduit()
	{
		while (true)
		{
			Debug.Log("compteur veille videoproduit démarré");
			yield return new WaitForSeconds(61); // on attend X secondes pour lancer l'animation de veille
			Debug.Log("compteur veille videoproduit terminé");


			Net_Lancementexperience le = new Net_Lancementexperience();

			SendClient1(0, 1, le);
			SendClient2(1, 2, le);
			SendClient3(2, 3, le);

			client1_clicked = false;
			client2_clicked = false;
			client3_clicked = false;
			break;

		}
	}
	#endregion

	#region Send
	public void SendClient(int recHost, int cnnId, NetMsg msg)
	{
		byte[] buffer = new byte[BYTE_SIZE];

		BinaryFormatter formatter = new BinaryFormatter();
		MemoryStream ms = new MemoryStream(buffer);
		formatter.Serialize(ms, msg);

		if (recHost == 0)
			NetworkTransport.Send(HostId, cnnId, reliableChannel, buffer, BYTE_SIZE, out error);
		else
			NetworkTransport.Send(WebHostId, cnnId, reliableChannel, buffer, BYTE_SIZE, out error);
	}


	public void SendClient1(int recHost, int cnnId, NetMsg msg)
	{
		byte[] buffer = new byte[BYTE_SIZE];

		BinaryFormatter formatter = new BinaryFormatter();
		MemoryStream ms = new MemoryStream(buffer);
		formatter.Serialize(ms, msg);

		NetworkTransport.Send(HostId, 1, reliableChannel, buffer, BYTE_SIZE, out error);

	}

	public void SendClient2(int recHost, int cnnId, NetMsg msg)
	{
		byte[] buffer = new byte[BYTE_SIZE];

		BinaryFormatter formatter = new BinaryFormatter();
		MemoryStream ms = new MemoryStream(buffer);
		formatter.Serialize(ms, msg);

		NetworkTransport.Send(HostId, 2, reliableChannel, buffer, BYTE_SIZE, out error);

	}

	public void SendClient3(int recHost, int cnnId, NetMsg msg)
	{
		byte[] buffer = new byte[BYTE_SIZE];

		BinaryFormatter formatter = new BinaryFormatter();
		MemoryStream ms = new MemoryStream(buffer);
		formatter.Serialize(ms, msg);

		NetworkTransport.Send(HostId, 3, reliableChannel, buffer, BYTE_SIZE, out error);
	}
	#endregion
}
