import type APIViewModel from "../models/account/APIViewModel";
import type LoginViewModel from "../models/account/LoginViewModel";
import type RegisterViewModel from "../models/account/RegisterViewModel";
import type DashboardViewModel from "../models/account/DashboardViewModel";
import Config from "../objects/Config";
import Session from "../objects/Session";
import DomainService from "../services/DomainService";
import UserService from "../services/UserService";
import ArrayUtility from "../utilities/ArrayUtility";
import Controller from "./Controller";
import type DomainsViewModel from "../models/account/DomainsViewModel";

export default class AccountController extends Controller {
	public async Login_Get_AllowAnonymous() {
		if (this.session) {
			return this.redirectToAction("dashboard");
		}

		return this.view();
	}

	public async Login_Post_AllowAnonymous(loginViewModel: LoginViewModel) {
		if (typeof(loginViewModel.username) !== "string" || typeof(loginViewModel.password) !== "string") {
			return this.badRequest();
		}

		const user = await UserService.AuthenticateUser(loginViewModel.username, loginViewModel.password);
		if (!user) {
			loginViewModel.password = "";
			loginViewModel.message = "Username or Password is incorrect";

			return this.view(loginViewModel);
		}

		Session.AssignUserSession(this.res, user);

		return this.redirectToAction("dashboard");
	}

	public async Register_Get_AllowAnonymous() {
		if (this.session) {
			return this.redirectToAction("dashboard");
		}

		return this.view();
	}

	public async Register_Post_AllowAnonymous(registerViewModel: RegisterViewModel) {
		if (typeof(registerViewModel.username) !== "string" || typeof(registerViewModel.password) !== "string" || typeof(registerViewModel.registerKey) !== "string" ||  typeof(registerViewModel.password2) !== "string" || typeof(registerViewModel.email) !== "string") {
			return this.badRequest();
		}

		if (registerViewModel.registerKey !== Config.accounts.signup.key) {
			registerViewModel.password = "";
			registerViewModel.password2 = "";
			registerViewModel.message = "Incorrect Registration Key.";

			return this.view(registerViewModel);
		}

		const username = registerViewModel.username.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
		if (!await UserService.CreateUser(1, username, registerViewModel.email.trim(), registerViewModel.password)) {
			registerViewModel.password = "";
			registerViewModel.password2 = "";
			registerViewModel.message = "Sorry! That username is already taken.";

			return this.view(registerViewModel);
		}

		const user = await UserService.GetUserByUsername(username);
		if (!user) {
			registerViewModel.password = "";
			registerViewModel.password2 = "";
			registerViewModel.message = "Failed to create your account, please try again later.";

			return this.view(registerViewModel);
		}

		Session.AssignUserSession(this.res, user);

		return this.redirectToAction("index", "home");
	}

	public async Index_Get_AllowAnonymous() {
		if (this.session) {
			return this.redirectToAction("dashboard");
		}

		return this.redirectToAction("login");
	}

	public async Dashboard_Get() {
		if (!this.session) {
			return this.redirect("/");
		}

		const dashboardViewModel: DashboardViewModel = {
			recentUploads: await UserService.GetRecentUploads(this.session.userId),
			domains: ArrayUtility.ToIdKeyedDict(await DomainService.LoadDomains()),

			mediaCounts: await UserService.GetUserMediaCounts(this.session.userId),
			mediaCount: await UserService.GetTotalMediaCount(this.session.userId),
			mediaSize: await UserService.GetTotalMediaSize(this.session.userId)
		}

		return this.view(dashboardViewModel);
	}

	public async Domains_Get() {
		const domainsViewModel: DomainsViewModel = {
			domains: await UserService.GetDomains(this.session.userId)
		};

		console.log(domainsViewModel);

		return this.view(domainsViewModel);
	}

	public async Media_Get() {
		return this.view();
	}

	public async API_Get() {
		const user = await UserService.GetUser(this.session.userId);
		if (!user) {
			return this.forbidden();
		}

		const apiViewModel: APIViewModel = {
			apiKey: user.ApiKey,
			uploadKey: user.UploadKey
		};

		return this.view(apiViewModel);
	}

	public async Logout_Get_AllowAnonymous() {
		Session.Clear(this.req.cookies, this.res);

		return this.redirect("/");
	}
}