import { getCookies } from '@std/http/cookie';
import { SESSIONS } from '../models/session.ts';
import { verifyTotp } from './totp.ts';
import { USER, USERS } from '../models/user.ts';
import * as CANNED_RESPONSES from './canned_responses.ts';
import { EVENT } from '../models/event.ts';

export type PRECHECK = (req: Request, meta: Record<string, any>) => Promise<Response | undefined> | Response | undefined;
export type PRECHECK_TABLE = Record<string, PRECHECK[]>;

export const AUTHED_BEFORE_COOKIE_ID: string = Deno.env.get('AUTHED_BEFORE_COOKIE_ID') ?? 'authed_before';
export const SESSION_ID_TOKEN: string = Deno.env.get('SESSION_ID_TOKEN') ?? 'session_id';
export const SESSION_SECRET_TOKEN: string = Deno.env.get('SESSION_SECRET_TOKEN') ?? 'session_secret';
export const TOTP_TOKEN: string = Deno.env.get('TOTP_TOKEN') ?? 'totp';

export async function get_session(request: Request, meta: Record<string, any>): Promise<undefined> {
	meta.now = meta.now ?? Date.now();
	meta.cookies = meta.cookies ?? getCookies(request.headers);
	meta.session_id = request.headers.get(`x-${SESSION_ID_TOKEN}`) ?? meta.cookies[SESSION_ID_TOKEN] ?? '';
	meta.session = meta.session_id?.length ? await SESSIONS.get(meta.session_id) : null;
	meta.valid_session = !!meta.session && meta.now < new Date(meta.session.timestamps.expires).valueOf();

	meta.request_totp = request.headers.get(`x-${TOTP_TOKEN}`) ?? meta.cookies[TOTP_TOKEN] ?? '';
	meta.valid_totp = meta.valid_session && meta.session && meta.request_totp ? await verifyTotp(meta.request_totp, meta.session.secret) : false;
}

export async function get_user(request: Request, meta: Record<string, any>): Promise<undefined> {
	meta.now = meta.now ?? Date.now();
	meta.cookies = meta.cookies ?? getCookies(request.headers);

	meta.user = meta.valid_totp && meta.session ? await USERS.get(meta.session.user_id) : null;
}

export function require_user(
	_request: Request,
	meta: Record<string, any>
): undefined | Response {
	if (!meta.user) {
		console.dir({
			require_user: true,
			meta
		});
		return CANNED_RESPONSES.permission_denied();
	}
}

export function user_has_create_permission_for_event(user: USER, event: EVENT) {
	return user.permissions.includes('events.create.' + event.type) || (Deno.env.get('DENO_ENV') === 'test' && event.type === 'test');
}
export function user_has_write_permission_for_event(user: USER, event: EVENT) {
	return user.permissions.includes('events.write.' + event.type) || (Deno.env.get('DENO_ENV') === 'test' && event.type === 'test');
}
