import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import Database from '@ioc:Adonis/Lucid/Database';
import Config from '@ioc:Adonis/Core/Config';
import User from 'app/Models/User';
import { Exception } from '@adonisjs/core/build/standalone';

const roleTable = Config.get('rolePermission.role_table', 'roles');
const userRoleTable = Config.get('rolePermission.user_role_table', 'link_accounts_roles');


// node ace make:middleware role
export default class Role {
	// .middleware(['auth', 'role:admin,moderator'])
	public async handle(
		{ auth, response }: HttpContextContract,
		next: () => Promise<void>,
		userRoles: string[]
	) {
		// Check if user is logged-in or not.
		// let expression = "";
		// if (Array.isArray(args)) {
		// 	expression = args.join(" || ");
		// }

		let user = await auth.user;
		if (!user) {
			return response.unauthorized({ error: 'Must be logged in' });
		}

		let hasRole = await this.checkHasRoles(user, userRoles);
		if (!hasRole) {
			// return response.unauthorized({
			// 	error: `Doesn't have required role(s): ${userRoles.join(',')}`,
			// 	// error: `Doesn't have required role(s)`,
			// });
			throw new Exception(`Doesn't have required role(s): ${userRoles.join(',')}`, 401);
		}

		// code for middleware goes here. ABOVE THE NEXT CALL
		await next();
	}

	private async checkHasRoles(user: User, userRoles: string[]): Promise<boolean> {
		// await user.load("roles");
		// const ok = user.roles.map((role) => role.name);
		// const roles = await user.getRoles();

		let rolePlaceHolder = '(';
		let placeholders = new Array(userRoles.length).fill('?');
		rolePlaceHolder += placeholders.join(',');
		rolePlaceHolder += ')';

		// const roles = await user
		// 	.related('roles')
		// 	.query()
		// 	.count('*')	// .select('name')
		// 	.whereIn('name', userRoles);
		// // .groupBy('name');

		// select count(*) as roleCount
		// from gba.roles
		// inner join gba.link_accounts_roles
		// on "roles"."id" = "link_accounts_roles"."role_id"
		// where ("name" in ('administrator', 'editor')) and ("link_accounts_roles"."account_id" = 1)

		let {
			rows: {
				0: { rolecount },
			},
		} = await Database.rawQuery(
			'SELECT count("r"."id") as roleCount FROM ' +
				roleTable +
				' r INNER JOIN ' +
				userRoleTable +
				' ur ON r.id=ur.role_id WHERE "ur"."account_id"=? AND "r"."name" in ' +
				rolePlaceHolder +
				' LIMIT 1',
			[user.id, ...userRoles]
		);

		return rolecount > 0;
	}
}
