// import io from 'socket.io-client';

import api from '../script/axiosApi.tsx';

// import { useEffect, useRef } from 'react';
import io from 'socket.io-client';
// const socket = io('http://192.168.1.14:4000');
// const socket = io('http://86.209.110.20:4000');
// const socket = io('http://172.29.113.91:4000');

interface GameProps {
	privateParty: boolean,
	username?: string
	gameId?: number
}

function DrawCanvas(option: number, gameParam: GameProps) {

	console.log(`option= ${option}`);
	const superpowerModifier = option & 1;  // Retrieves the superpower modifier
    const obstacleModifier = (option >> 1) & 1;  // Retrieves the obstacle modifier
    const speedModifier = (option >> 2) & 1;  // Retrieves the speed modifier

    console.log(`superpowerModifier = ${superpowerModifier}`);
    console.log(`obstacleModifier = ${obstacleModifier}`);
    console.log(`speedModifier = ${speedModifier}`);
	
	
	
	// const socketRef = useRef(null);
	// socketRef.current = io('http://localhost:4000');
	
	function launchGame()
	{
		if (!gameParam.privateParty)
		{
			console.log("laucnh matchmaking")
			matchmaking();
		}
		else if (!gameParam.gameId)
		{
			console.log("laucnh private")
			privateParty();
		}
		else
		{
			console.log("join private")
			joinPrivateParty();
		}
	}
	
	// const socket = socketRef.current
	console.log("start function");
	
	// let canvas: HTMLElement | null;
	const canvas = document.getElementById('myCanvas') as HTMLCanvasElement | null;;
	if (!canvas)
		return ;

	const ctx = canvas.getContext('2d');
	if(!ctx)
		return ;
	
	const socket = io('http://' + process.env.REACT_APP_SOCKET_URL + ':4000', { transports: ['polling'] });
	// useEffect(() => {
		// 	console.log("useeffect?????????????????")
	// 	return () => {
	// 		console.log("000000000000000000000000000000000")
	// 	  socketRef.current.disconnect();
	// 	};
	//   }, []);


//========================================================================================================
//========================================================================================================
//                                        Var Declaration			                                  
//========================================================================================================
//========================================================================================================

	//socket
	let myId = 0;
	let gameId = 0;
	let opName: string
	let opRank: number;

	//general canvas
	let running = true;
	const scale = window.devicePixelRatio; 
	canvas.width = canvas.offsetWidth;
	// canvas.height = canvas.width * 0.7
	canvas.height = canvas.offsetHeight;

	//paddle var
	let paddleWidth = canvas.width * 0.01;
	let paddleHeight = canvas.height * 0.25;
	let paddleY = canvas.height / 2 - (paddleHeight / 2);
	let paddleX = canvas.width / 40;
	let paddleSpeed = canvas.height / 40;
	
	//opponent var
	let opPaddleHeight = canvas.height * 0.25;
	let oPaddleY = paddleY;

	//mouse and touch
	let lastMouseY = 0;
	let lastTouchY = 0;

	//ball var
	let ballX = canvas.width / 2;
	let ballY = canvas.height / 2;

	//ball display
	let ballRadius = canvas.width * 0.01;
	let circleRadius = ballRadius * 3;
	ctx.lineWidth = (canvas.width / 300);

	//ball vector
	let vX = 0;
	let vY = 0;

	//score
	let myScore = 0;
	let hisScore = 0;
	const maxScore = 5;
	
	let lastUpdateTime = performance.now();
	let lastPower = 0;


	const maxAngle = 50;
	let maxBounceAngle = (maxAngle * Math.PI) / 180;

//========================================================================================================
//========================================================================================================
//                                       Socket ON			                                  
//========================================================================================================
//========================================================================================================

socket.on('pong:win', async () => {
	myScore = maxScore;
	console.log("instant win opponent disconnect")
	// const data = {
	// 	myScore: myScore,
	// 	opScore: hisScore,
	// 	opName: opName,
	// 	opRank: opRank,
	// };

	// await api.post('/win', data);
	console.log("after request1")
	await api.post('/status', {status: 1});
	console.log("after request2")
	//disconnect ?
	running = false;
	socket.emit('pong:disconnect', {id: myId});
	console.log("before reload")
	// window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong");
	// window.location.reload();
	return ;
	// console.log("send all ?? win");

});

socket.on('pong:privateId', async (data) => {
	console.log("private id = ", data)
	try{
		await api.post("/partyInvite", {username: gameParam.username, gameId: data});
	} catch(err) {
		console.log(err)
	}
});

socket.on('pong:gameId', async (data) => {
	console.log("gameId received");
	gameId = data.gameId;
	console.log("gameid = ", gameId);
	console.log("data gameid = ", data);
  
	try {
	  let response = await api.get('/profile');
	  const myName = response.data.username;
	  response = await api.get('/rank');
	  await api.post('/status', {status: 2});
	  opRank = response.data
	  console.log(`rank= ${opRank}`);
	  console.log(`myname= ${myName}`);

	  const info = {
		id: myId,
		name: myName,
		gameId: gameId,
		rank: opRank,
	  };
  
	  console.log("emit to name");
	  socket.emit('pong:name', info);
	  if (data.id === myId)
	  {
		console.log("myId= true")
	  	vX = 0.0005;
	  }
	  else
	  {
		console.log("myId= false")
	  	vX = -0.0005;
	  }
	} catch (error) {
	  console.log(error);
	  // Handle error here
	  return;
	}
  });

socket.on('pong:name', (data) => {
	opName = data.name;
	// if (data.myId === myId)
	// 	vX = 0.0001;
	// else
	// 	vX = -0.0001;
	console.log(`opponent Name= ${opName}`)
});

socket.on('connect', () => {
	console.log('Connected to NestJS server');
});

socket.on('pong:clientId', (data) => {
	console.log("receive id")
	myId = data;
	console.log(`id is= ${myId}`)
	launchGame();
});

socket.on('pong:info', (data) => {
	oPaddleY = (data.paddleY / data.height) * canvas.height//canvas.height - data.ballY;
	ballX = canvas.width - (data.ballX * (canvas.width / data.width));//- data.ballX;
	ballY = ((data.ballY / data.height) * canvas.height)//canvas.height - data.ballY;

	vX = -data.vX;
	vY = data.vY;
});

socket.on('pong:paddle', (data) => {
	console.log("paddle info receive")
	oPaddleY = (data.paddleY / data.height) * canvas.height
});

socket.on('pong:power', (data) => {
	console.log("paddle info receive")
	
	oPaddleY = 0;
	opPaddleHeight = canvas.height;

	setTimeout(() => {
		// code à exécuter après 5 secondes
		opPaddleHeight = canvas.height * 0.25;
		oPaddleY = canvas.height / 2 - paddleHeight / 2;
		console.log('Cinq secondes se sont écoulées.');
	}, 5000);
	// oPaddleY = (data.paddleY / data.height) * canvas.height
});

socket.on('pong:point', (data) => {
	// hisScore += 1;
	console.log("gain point");
	// if (vX != 0)
	// {
		// console.log("up point");
	myScore = data.point;
	// }
	vX = -0.0005;
	vY = 0;
	ballX = canvas.width / 2;
	ballY = canvas.height / 2;
});

socket.on('pong:hisPoint', (data) => {
	// hisScore += 1;
	console.log("myPointawdawdawdawd point");
	// if (vX != 0)
	// {
		// console.log("up point");
	hisScore = data.point;
	// }
	vX = -0.0005;
	vY = 0;
	ballX = canvas.width / 2;
	ballY = canvas.height / 2;
	// send_forced_info();
});

//========================================================================================================
//========================================================================================================
//                                       Socket EMIT			                                  
//========================================================================================================
//========================================================================================================

	function matchmaking()
	{
		console.log(`id ion matcj= ${myId}`)
		const info = {
			id: myId,
			option: option,
		};
		socket.emit('pong:matchmaking', info);
	}

	function privateParty()
	{
		console.log(`id private party= ${myId}`)
		const info = {
			id: myId,
			option: option,
		};
		socket.emit('pong:privateParty', info);
	}

	function joinPrivateParty()
	{
		console.log(`id private party= ${myId}`)
		const info = {
			id: myId,
			gameId: gameParam.gameId,
			option: option,
		};
		socket.emit('pong:joinParty', info);
	}
	
	function send_info()
	{
		if (!gameId || !canvas)
			return ;
		const info = {
			id: myId,
			width: canvas.width,
			height: canvas.height,
			paddleY: paddleY,
			vX: vX,
			vY: vY,
			ballX: ballX,
			ballY: ballY,
			gameId: gameId,
		};
		socket.emit('pong:message', info);
	}

	function send_point()
	{
		if (!gameId || !canvas)
			return ;
		console.log("send point");
		const info = {
			id: myId,
			gameId: gameId,
			point: hisScore,
		}
		socket.emit('pong:point', info);
		vX = 0.0005;
	}

	function send_my_point()
	{
		if (!gameId || !canvas)
			return ;
		// console.log("send point");
		const info = {
			id: myId,
			gameId: gameId,
			point: myScore,
		}
		socket.emit('pong:myPoint', info);
		myScore++;
		vX = 0.0005;
		vY = 0;
		ballX = canvas.width / 2;
		ballY = canvas.height / 2;
		send_forced_info();
	}

	function send_paddle_info()
	{
		if (!gameId || !canvas)
			return ;
		const info = {
			id: myId,
			paddleY: paddleY,
			// width: canvas.width,
			height: canvas.height,
			gameId: gameId,
		};
		socket.emit('pong:paddle', info);
	}

	function use_power()
	{
		if (!canvas)
			return ;
		const info = {
			gameId: gameId,
			width: canvas.width,
			height: canvas.height,
			id: myId,
		}
		socket.emit('pong:power', info);
	}

	function send_forced_info()
	{
		if (!gameId || !canvas)
			return ;
		const info = {
			gameId: gameId,
			width: canvas.width,
			height: canvas.height,
			id: myId,
			paddleY: paddleY,
			vX: vX,
			vY: vY,
			ballX: ballX,
			ballY: ballY,
		};
		socket.emit('pong:forced', info);
	}

//========================================================================================================
//========================================================================================================
//                                          Drawer
//========================================================================================================
//========================================================================================================

	function drawcenter()
	{
		// ctx.restore();
		if (!ctx || !canvas)
			return ;
		ctx.fillStyle = 'white';
		ctx.fillRect(canvas.width / 2 - ctx.lineWidth / 2, 0, canvas.width / 300, canvas.height);
		
		ctx.beginPath();
		// ctx.lineWidth = 5;
		ctx.arc(canvas.width / 2, canvas.height / 2, circleRadius, 0, 2 * Math.PI);
		ctx.strokeStyle = 'white'; // couleur de dessin
		ctx.stroke(); // dessin du contour

		ctx.font = canvas.width * 0.1 + "px Arial";
		ctx.textAlign = "center";
		ctx.textBaseline = "middle";
		ctx.fillText(myScore.toString(), canvas.width/4, canvas.height/8);
		ctx.fillText(hisScore.toString(), canvas.width/1.25, canvas.height/8);
	}

	function drawPaddle() {
		if (!ctx || !canvas)
			return ;
		ctx.fillStyle = 'white';
		ctx.fillRect(paddleX, paddleY, paddleWidth, paddleHeight);
		ctx.fillRect(canvas.width - paddleX - paddleWidth, oPaddleY, paddleWidth, opPaddleHeight);
	}

	function drawball()
	{
		if (!ctx)
			return ;
		ctx.beginPath();
		ctx.arc(ballX, ballY, ballRadius, 0, 2 * Math.PI);
		// ctx.lineWidth = 2;
		ctx.fillStyle = 'red ';
		ctx.fill();
	}

 
//========================================================================================================
//========================================================================================================
//                                           Loop
//========================================================================================================
//========================================================================================================


// while (!gameId)
// 	;

  // Define a function to stop the drawing process
  const stopDrawCanvas = async () => {
    running = false;

	console.log("stopDrawCanvas 1")

	if (gameParam.privateParty && !gameId) //delete invite
	{
		console.log("stopDrawCanvas2")
		try{
			// const info = {
				// 	id: myId,
				// 	option: option,
				// };
				// await api.post("status", {status: 1});
				await api.post('/status', {status: 1});
				await api.post("deleteInvite", {username: gameParam.username})
		}
		catch (err){
			console.log(err)
		}
	}
	socket.emit('pong:disconnect', {id: myId});
	window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong");
	// window.location.reload();
    // Perform any necessary cleanup tasks
    // ...
  };

async function draw(timestamp: number)
{
	console.log("turning, running= ", running);
	if (!running)
	{
		window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong")
		return ;
	}
	if (!gameId || !canvas )
	{
		// console.log("nogameid score= ", myScore);
		requestAnimationFrame(draw);
		return ;
	}
	if (myScore === maxScore || hisScore === maxScore)
	{
		console.log("maxScore!!!!")
		const data = {
			myScore: myScore,
			opScore: hisScore,
			opName: opName,
			opRank: opRank,
		};
		if (myScore === maxScore)
		{
			await api.post('/win', data);
			await api.post('/status', {status: 1});
			//disconnect ?
			socket.emit('pong:disconnect', {id: myId});

			console.log("send all ?? win");	
		}
		else
		{
			await api.post('/loss', data);
			await api.post('/status', {status: 1});
			socket.emit('pong:disconnect', {id: myId});
			//disconnect ?
			console.log("send loose");
		}
		window.location.replace("http://" + process.env.REACT_APP_BASE_URL + "/pong");
		// window.location.reload();
		return ;
	}

	const deltaTime = timestamp - lastUpdateTime;
	lastUpdateTime = timestamp;
	ballX += vX * deltaTime * canvas.width;
	ballY += vY * deltaTime * canvas.height;

	if (!ctx)
		return ;
		// requestAnimationFrame(draw);
	ctx.clearRect(0, 0, canvas.width, canvas.height);
	drawPaddle();
	drawcenter();
	drawball();
	is_collision();
	is_out();
	requestAnimationFrame(draw);
}



//========================================================================================================
//========================================================================================================
//                                       Logical Part
//========================================================================================================
//========================================================================================================

	function updateVector()
	{
		const relativeBallY = ballY - (paddleY + paddleHeight / 2);
		const normalizedRelativeBallY = relativeBallY / (paddleHeight / 2);
		const bounceAngle = normalizedRelativeBallY * maxBounceAngle;

		vY = vX * Math.sin(-bounceAngle);
		if (vX < 0)
			vX = -vX; 
		if (speedModifier)
		{
			if (vX > 0)
				vX += 0.0001;
			else
				vX -= 0.0001;
		}
	}


	function updatePaddlePosition(newY: number)
	{

		if (canvas && newY >= 0 && newY <= canvas.height - paddleHeight)
			paddleY = newY;
	}

	function is_collision()
	{
		if (!canvas)
			return ;
		if (ballX <= paddleX + paddleWidth + ballRadius)
		{
			if (ballY <= paddleY + paddleHeight + ballRadius && ballY >= paddleY - ballRadius)//touch paddle
			{
				if (ballX +  ballRadius > paddleX && ballX - ballRadius < paddleX + paddleWidth)
				{
					console.log("hehe here")
					ballX = paddleX + paddleWidth + ballRadius;
				}
				updateVector();
			}
			send_info();
			return ;
		}
		if (ballY - ballRadius - 2 <= 0 || ballY + ballRadius + 2 >= canvas.height) //touch up or down wall
		{
			// if ()
			vY = -vY;
			if (ballY > (canvas.height / 2))//down wall
				ballY = canvas.height - ballRadius - 2
			else
				ballY = ballRadius + 2
			// send_info();
		}
	}

	function is_out()
	{
		if (!canvas)
			return ;
		if (ballX < 0)
		{
			if (ballY <= paddleY + paddleHeight + ballRadius && ballY >= paddleY - ballRadius)
			{
				console.log('true hehe');
				ballX = paddleX + paddleWidth + ballRadius;
				updateVector();
				return ;
			}
			ballX = canvas.width / 2;
			ballY = canvas.height / 2;
			vX = 0.0005;
			vY = 0;
			hisScore += 1;
			send_point();
			// send_forced_info();
		}
		if (ballX > (canvas.width * 1.2) && ballX - (vX * 2) > canvas.width)
		{
			console.log("ball out win point pls")
			send_my_point();
			// if (ballX > canvas.width * 2)
			// console.log("win point")
			// if (ballY <= paddleY + paddleHeight + ballRadius && ballY >= paddleY - ballRadius)
			// {
			// 	console.log('true hehe');
			// 	ballX = paddleX + paddleWidth + ballRadius;
			// 	updateVector();
			// 	return ;
			// }
			// ballX = canvas.width / 2;
			// ballY = canvas.height / 2;
			// vX = 0;
			// vY = 0;
			// hisScore += 1;
			// send_point();
			// // send_forced_info();
		}

	}



//========================================================================================================
//========================================================================================================
//                                 Key/Mouse/Finger Listener
//========================================================================================================
//========================================================================================================

    document.addEventListener('mousemove', event => {
        const mouseY = event.clientY;

        if (!lastMouseY)
		{
            lastMouseY = mouseY;
            return;
        }
        const newY = mouseY > lastMouseY ? paddleY - (lastMouseY - mouseY) : paddleY + (mouseY - lastMouseY);
        updatePaddlePosition(newY);
        lastMouseY = mouseY;
		send_paddle_info();
    });

    document.addEventListener("touchmove", event => {
        const touchY = event.touches[0].pageY;

        // if (!lastTouchY)
		// {
		// 	vX = -0.01;
        //     lastTouchY = touchY;
        //     return;
        // }
        const newY = touchY > lastTouchY ? paddleY - (lastTouchY - touchY) : paddleY + (touchY - lastTouchY);
        updatePaddlePosition(newY);
        lastTouchY = touchY;
		send_paddle_info();
    });

	document.addEventListener("keydown", event => {
		// console.log(event.code);
		if (event.code === "ArrowUp")
		{
			if ((paddleY - paddleSpeed) > 0)
		  		paddleY -= paddleSpeed; // déplacer la raquette vers le haut
			send_paddle_info();
		}
		else if (event.code === "ArrowDown")
		{
			if (paddleY + paddleSpeed < canvas.height - paddleHeight)
				paddleY += paddleSpeed; // déplacer la raquette vers le bas
			send_paddle_info();
		}
		else if (event.code === "Space")//space
		{
			console.log('vx change to -1');
			vX = -0.0001;

			// ballSpeed = 0.0001;
			vY = 0;
			send_forced_info();
			// vX = 0.0001;
		}
		else if (event.code === "KeyE")
		{
			// console.log('vx change to -1');
			vX = 0;
			vY = 0;
			ballX = canvas.width / 2;
			ballY = canvas.height / 2;
			send_forced_info();
		}
		else if (event.code === "KeyQ" )
		{
			if (vX < 0.003 * canvas.width && vX > -0.003 * canvas.width)
			{
				if (vX > 0)
					vX += 0.0001;
				else
					vX -= 0.0001;
			}
			send_forced_info();
		}
		else if (event.code === "KeyW")
		{
			let date = new Date();
			console.log("last time =", date.getTime() - lastPower)
			if (date.getTime() - lastPower < 15000)//10000 + 5000
				return ;
			if (!superpowerModifier)
				return ;
			paddleY = 0;
			paddleHeight = canvas.height;
			use_power();
			setTimeout(() => {
				// code à exécuter après 5 secondes
				paddleHeight = canvas.height * 0.25;
				paddleY = canvas.height / 2 - paddleHeight / 2;
				console.log('Cinq secondes se sont écoulées.');
			  }, 5000);
			date = new Date();
			lastPower = date.getTime();
			// console.log("date= ", date.getTime())
		}
	});

	requestAnimationFrame(draw);
	console.log("retuuuuuuuuuuurn")
	return (stopDrawCanvas);
}

export default DrawCanvas