import { Controller, UseGuards, HttpException, HttpStatus, Get, Post, Delete, Body, Req, Res } from '@nestjs/common';
import { AuthenticateGuard, TwoFactorGuard } from 'src/auth/42/guards/42guards';
import { ConnectedSocket } from '@nestjs/websockets';
import { ChatService } from './chat.service';
import { User } from 'src/users/entities/user.entity';
import { PartialUsersDto } from 'src/users/dto/partial-users.dto';
import { roomDto } from './dto/room.dto';
import { setCurrentRoomDto } from './dto/setCurrentRoom.dto';
import { ChatGateway } from './chat.gateway';
import { socketDto } from './dto/socket.dto';
import { Chatroom } from './entities/chatroom.entity';

@Controller('chat')
export class ChatController {

	constructor(
		private chatService: ChatService,
		private chatGateway: ChatGateway,
	) {}

	// don't allow '+' because it's used in direct rooms name
	private allowed_chars = '-#!?_';
	private escape_chars(str)
	{
		return str.split("").join("\\");
	}


	@UseGuards(AuthenticateGuard)
	@UseGuards(TwoFactorGuard)
	@Get('myrooms')
	async getMyRooms(@Req() req, @Res() res): Promise<void>
	{
		console.log("- in getMyRooms controller");

		let fields = ["name", "type", "users"];
		const rooms = await this.chatService.getMyRooms(req.user.username, fields);

		res.status(HttpStatus.OK).json({ rooms: rooms });

		console.log("- out getMyRooms controller");
	}

	@UseGuards(AuthenticateGuard)
	@UseGuards(TwoFactorGuard)
	@Get('allrooms')
	async getAllRooms(@Req() req, @Res() res): Promise<void>
	{
		console.log("- in getAllRooms controller");

		const rooms: roomDto[] = await this.chatService.getAllOtherRoomsAndUsers(req.user.username)
		console.log("--- rooms:", rooms);
		res.status(HttpStatus.OK).json({ rooms: rooms });

		console.log("- out getAllRooms controller");
	}

	@UseGuards(AuthenticateGuard)
	@UseGuards(TwoFactorGuard)
	@Get('current')
	async setCurrentRoom(@Body() setCurrentRoomDto: setCurrentRoomDto, @Req() req, @Res() res): Promise<void>
	{
		console.log("- in setCurrentRoom controller");

		const response = await this.chatService.setCurrentRoom(req.user.username, setCurrentRoomDto.name);
		res.status(HttpStatus.OK).json({ message: response });

		console.log("- out setCurrentRoom controller");
	}

	@UseGuards(AuthenticateGuard)
	@UseGuards(TwoFactorGuard)
	@Get('allowedchars')
	async allowedChars(@Res() res): Promise<void>
	{
		console.log("- in allowedChars controller");

		res.status(HttpStatus.OK).json({ chars: this.allowed_chars });

		console.log("- out allowedChars controller");
	}

	@UseGuards(AuthenticateGuard)
	@UseGuards(TwoFactorGuard)
	@Post('create')
	async createRoom(@Body() room: roomDto, @Req() req, @Res() res): Promise<void>
	{
		console.log("- in createRoom controller");

		let chars = this.escape_chars(this.allowed_chars);
		let regex_base = `[a-zA-Z0-9\\s${chars}]`;
		let test_regex = new RegExp(`^${regex_base}+$`);
		if (test_regex.test(room.name) === false)
		{
			let forbidden_chars = room.name.replace(new RegExp(regex_base, "g"), "");
			throw new HttpException(`Your room name can not contains these characters : ${forbidden_chars}`, HttpStatus.UNPROCESSABLE_ENTITY);
		}

		await this.chatService.addUserToNewRoom(req.user.username, room);
		res.status(HttpStatus.OK).json({ room: room });

		console.log("- out createRoom controller");
	}

	@UseGuards(AuthenticateGuard)
	@UseGuards(TwoFactorGuard)
	@Post('join')
	async joinRoom(@Body() room: roomDto, @Req() req, @Res() res): Promise<void>
	{
		console.log("- in joinRoom controller");

		let response = "";
		if (room.type === 'direct')
			throw new HttpException(`cannot join a direct messages room`, HttpStatus.CONFLICT);
		else if (room.type === 'user')
		{
			room.type = 'direct';
			room.users = [room.name, req.user.username];
			room.name += ` + ${req.user.username}`;
			await this.chatService.addUserToNewRoom(req.user.username, room);
		}
		else
			await this.chatService.addUserToRoom(req.user.username, room.name);

		let socket: socketDto = this.chatGateway.sockets.get(req.user.username);
		await this.chatService.socketJoinRoom(socket, room.name);
		res.status(HttpStatus.OK).json({ room: room });

		console.log("- out joinRoom controller");
	}

	@UseGuards(AuthenticateGuard)
	@UseGuards(TwoFactorGuard)
	@Post('change')
	async changeRoom(@Body() room: roomDto, @Req() req, @Res() res): Promise<void>
	{
		console.log("- in changeRoom controller");

		const response = await this.chatService.setCurrentRoom(req.user.username, room.name);
		let socket: socketDto = this.chatGateway.sockets.get(req.user.username);
		await this.chatService.socketChangeRoom(socket, room.name);
		res.status(HttpStatus.OK).json({ room: room });

		console.log("- out changeRoom controller");
	}

	@UseGuards(AuthenticateGuard)
	@UseGuards(TwoFactorGuard)
	@Post('leave')
	async leaveRoom(@Body() body)
	{
		console.log("- in leaveRoom controller");
		console.log("- out leaveRoom controller");
	}

	@UseGuards(AuthenticateGuard)
	@UseGuards(TwoFactorGuard)
	@Get('messages')
	async getMessages(@Req() req, @Res() res): Promise<void>
	{
		console.log("- in getMessages controller");

		const messages = await this.chatService.getMessagesFromCurrentRoom(req.user.username);
		res.status(HttpStatus.OK).json({ messages: messages });

		console.log("- out getMessages controller");
	}

	@UseGuards(AuthenticateGuard)
	@UseGuards(TwoFactorGuard)
	@Get('roomusers')
	async getRoomUsers(@Req() req, @Res() res): Promise<void>
	{
		console.log("- in getRoomUsers controller");

		const room_name = await this.chatService.getCurrentRoomName(req.user.username);
		const room = await this.chatService.getRoomByName(room_name);
		const users = room.users;
		res.status(HttpStatus.OK).json({ users: users });

		console.log("- out getRoomUsers controller");
	}

	@UseGuards(AuthenticateGuard)
	@UseGuards(TwoFactorGuard)
	@Delete('removeuser')
	async removeUser(@Req() req, @Res() res): Promise<void>
	{
		console.log("- in removeUser controller");

		const room_name = await this.chatService.getCurrentRoomName(req.user.username);
		let response = await this.chatService.removeUserFromRoom(req.user.username, room_name);
		res.status(HttpStatus.OK).json({ message: response });

		console.log("- out removeUser controller");
	}

}

