import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import User from 'App/Models/User';
import Role from 'App/Models/Role';
import type { ModelQueryBuilderContract } from '@ioc:Adonis/Lucid/Orm';
import CreateUserValidator from 'App/Validators/CreateUserValidator';
import UpdateUserValidator from 'App/Validators/UpdateUserValidator';
import { RenderResponse } from '@ioc:EidelLev/Inertia';
// import { schema, rules } from '@ioc:Adonis/Core/Validator';

export default class UsersController {
	public async index({ auth, request, inertia }: HttpContextContract) {
		const page = request.input('page', 1);
		// const limit = 10

		let users: ModelQueryBuilderContract<typeof User, User> = User.query();

		if (request.input('search')) {
			// users = users.whereRaw('name like %?%', [request.input('search')])
			const searchTerm = request.input('search');
			users.where('login', 'ilike', `%${searchTerm}%`);
		}

		if (request.input('sort')) {
			type SortOrder = 'asc' | 'desc' | undefined;
			let attribute = request.input('sort');
			let sort_order: SortOrder = 'asc';

			// if (strncmp($attribute, '-', 1) === 0) {
			if (attribute.substr(0, 1) == '-') {
				sort_order = 'desc';
				// attribute = substr(attribute, 1);
				attribute = attribute.substr(1);
			}
			// $users->orderBy($attribute, $sort_order);
			users.orderBy(attribute, sort_order);
		} else {
			// users.orderBy('created_at', 'desc');
			users.orderBy('id', 'asc');
		}

		// const users = await User.query().orderBy('login').paginate(page, limit);

		let usersResult = await users // User.query()
			// .orderBy('login')
			// .filter(qs)
			// .preload('focusInterests')
			// .preload('role')
			.paginate(page, 5);

		// var test = request.all();

		return inertia.render('Admin/User/Index', {
			// testing: 'this is a test',
			users: usersResult.toJSON(),
			filters: request.all(),
			can: {
				create: await auth.user?.can(['user-create']),
				edit: await auth.user?.can(['user-edit']),
				delete: await auth.user?.can(['user-delete']),
			},
		});
	}

	public async create({ inertia }: HttpContextContract) {
		// let rolesPluck = {};
		// (await Role.query().select('id', 'name')).forEach((user) => {
		// 	rolesPluck[user.id] = user.name;
		// });
		const roles = await Role.query().select('id', 'name').pluck('name', 'id');

		return inertia.render('Admin/User/Create', {
			roles: roles,
		});
	}

	public async store({ request, response, session }: HttpContextContract) {
		// node ace make:validator CreateUser
		try {
			//  Step 2 - Validate request body against  the schema
			await request.validate(CreateUserValidator);
			// console.log({ payload });
		} catch (error) {
			// Step 3 - Handle errors
			// return response.badRequest(error.messages);
			throw error;
		}
		const input = request.only(['login', 'email', 'password']);
		const user = await User.create(input);
		if (request.input('roles')) {
			const roles: Array<number> = request.input('roles');
			await user.related('roles').attach(roles);
		}

		session.flash('message', 'User has been created successfully');
		return response.redirect().toRoute('user.index');
	}

	public async show({ request, inertia }: HttpContextContract) {
		const id = request.param('id');
		const user = await User.query().where('id', id).firstOrFail();

		const roles = await Role.query().pluck('name', 'id');
		// const userHasRoles = user.roles;
		const userRoles = await user.related('roles').query().orderBy('name').pluck('id');

		return inertia.render('Admin/User/Show', {
			roles: roles,
			user: user,
			userHasRoles: userRoles,
		});
	}

	public async edit({ request, inertia }: HttpContextContract) {
		const id = request.param('id');
		const user = await User.query().where('id', id).firstOrFail();

		const roles = await Role.query().pluck('name', 'id');
		// const userHasRoles = user.roles;
		const userHasRoles = await user.related('roles').query().orderBy('name').pluck('id');
		// let test = Object.keys(userHasRoles).map((key) => userHasRoles[key]);
		return inertia.render('Admin/User/Edit', {
			roles: roles,
			user: user,
			userHasRoles: Object.keys(userHasRoles).map((key) => userHasRoles[key]), //convert object to array with role ids
		});
	}

	public async update({ request, response, session }: HttpContextContract) {
		// node ace make:validator UpdateUser
		const id = request.param('id');
		const user = await User.query().where('id', id).firstOrFail();

		// validate update form
		await request.validate(UpdateUserValidator);

		// password is optional
		let input;
		if (request.input('password')) {
			input = request.only(['login', 'email', 'password']);
		} else {
			input = request.only(['login', 'email']);
		}
		await user.merge(input).save();
		// await user.save();

		if (request.input('roles')) {
			const roles: Array<number> = request.input('roles');
			await user.related('roles').sync(roles);
		}

		session.flash('message', 'User has been updated successfully');
		return response.redirect().toRoute('user.index');
	}

	public async destroy({ request, response, session }: HttpContextContract) {
		const id = request.param('id');
		const user = await User.findOrFail(id);
		await user.delete();

		session.flash('message', `User ${user.login} has been deleted.`);
		return response.redirect().toRoute('user.index');
	}

	/**
	 * Show the user a form to change their personal information & password.
	 *
	 * @return — \Inertia\Response
	 */
	public accountInfo({  inertia, auth }: HttpContextContract): RenderResponse {
		const user = auth.user;
		// const id = request.param('id');
		// const user = await User.query().where('id', id).firstOrFail();

		return inertia.render('Admin/User/AccountInfo', {
			user: user,
		});
	}

	/**
	 * Save the modified personal information for a user.
	 *
	 * @param  HttpContextContract ctx
	 * @return : RedirectContract
	 */
	public async accountInfoStore({ request, response, auth, session }: HttpContextContract) {
		// validate update form
		await request.validate(UpdateUserValidator);

		const payload = request.only(['login', 'email']);
		auth.user?.merge(payload);
		const user = await auth.user?.save();
		//   $user = \Auth::user()->update($request->except(['_token']));
		let message;
		if (user) {
			message = 'Account updated successfully.';
		} else {
			message = 'Error while saving. Please try again.';
		}

		session.flash(message);
		return response.redirect().toRoute('admin.account.info');
		//->with('message', __($message));
	}
}
