import { DateTime } from 'luxon';
import { BaseModel, column, beforeSave, manyToMany, ManyToMany } from '@ioc:Adonis/Lucid/Orm';
import Hash from '@ioc:Adonis/Core/Hash';
import Role from './Role';
import Database from '@ioc:Adonis/Lucid/Database';
import Config from '@ioc:Adonis/Core/Config';

// export default interface IUser {
// 	id: number;
// 	login: string;
// 	email: string;
// 	// password: string;
// 	// createdAt: DateTime;
// 	// updatedAt: DateTime;
// 	// async (user): Promise<void>;
// }

const permissionTable = Config.get('rolePermission.permission_table', 'permissions');
const rolePermissionTable = Config.get('rolePermission.role_permission_table', 'role_has_permissions');

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

export default class User extends BaseModel {
	public static table = 'accounts';

	@column({ isPrimary: true })
	public id: number;

	@column()
	public login: string;

	@column()
	public email: string;

	@column({ serializeAs: null })
	public password: string;

	@column.dateTime({ autoCreate: true })
	public createdAt: DateTime;

	@column.dateTime({ autoCreate: true, autoUpdate: true })
	public updatedAt: DateTime;

	@beforeSave()
	public static async hashPassword(user) {
		if (user.$dirty.password) {
			user.password = await Hash.make(user.password);
		}
	}

	@manyToMany(() => Role, {
		pivotForeignKey: 'account_id',
		pivotRelatedForeignKey: 'role_id',
		pivotTable: 'link_accounts_roles',
	})
	public roles: ManyToMany<typeof Role>;

	// https://github.com/adonisjs/core/discussions/1872#discussioncomment-132289
	public async getRoles(this: User): Promise<string[]> {
		const test = await this.related('roles').query();
		return test.map((role) => role.name);
	}

	public async can(permissionNames: Array<string>): Promise<boolean> {
		// const permissions = await this.getPermissions()
		// return Acl.check(expression, operand => _.includes(permissions, operand))
		const hasPermission = await this.checkHasPermissions(this, permissionNames);
		return hasPermission;
	}

	private async checkHasPermissions(user: User, permissionNames: Array<string>): Promise<boolean> {
		let permissionPlaceHolder = '(';
		let placeholders = new Array(permissionNames.length).fill('?');
		permissionPlaceHolder += placeholders.join(',');
		permissionPlaceHolder += ')';

		let {
			rows: {
				0: { permissioncount },
			},
		} = await Database.rawQuery(
			'SELECT count("p"."name") as permissionCount FROM ' +
				roleTable +
				' r INNER JOIN ' +
				userRoleTable +
				' ur ON ur.role_id=r.id AND "ur"."account_id"=? ' +
				' INNER JOIN ' +
				rolePermissionTable +
				' rp ON rp.role_id=r.id ' +
				' INNER JOIN ' +
				permissionTable +
				' p ON rp.permission_id=p.id AND "p"."name" in ' +
				permissionPlaceHolder +
				' LIMIT 1',
			[user.id, ...permissionNames]
		);

		return permissioncount > 0;
	}
}

// export default User;
