import { publishMainStream } from "@/services/stream.js";
import define from "../../define.js";
import rndstr from "rndstr";
import config from "@/config/index.js";
import { Users, UserProfiles } from "@/models/index.js";
import { sendEmail } from "@/services/send-email.js";
import { ApiError } from "../../error.js";
import { validateEmailForAccount } from "@/services/validate-email-for-account.js";
import { HOUR } from "@/const.js";
import { comparePassword } from "@/misc/password.js";

export const meta = {
	requireCredential: true,

	secure: true,

	limit: {
		duration: HOUR,
		max: 3,
	},

	errors: {
		incorrectPassword: {
			message: "Incorrect password.",
			code: "INCORRECT_PASSWORD",
			id: "e54c1d7e-e7d6-4103-86b6-0a95069b4ad3",
		},

		unavailable: {
			message: "Unavailable email address.",
			code: "UNAVAILABLE",
			id: "a2defefb-f220-8849-0af6-17f816099323",
		},
	},
} as const;

export const paramDef = {
	type: "object",
	properties: {
		password: { type: "string" },
		email: { type: "string", nullable: true },
	},
	required: ["password"],
} as const;

export default define(meta, paramDef, async (ps, user) => {
	const profile = await UserProfiles.findOneByOrFail({ userId: user.id });

	// Compare password
	const same = await comparePassword(ps.password, profile.password!);

	if (!same) {
		throw new ApiError(meta.errors.incorrectPassword);
	}

	if (ps.email != null) {
		const available = await validateEmailForAccount(ps.email);
		if (!available) {
			throw new ApiError(meta.errors.unavailable);
		}
	}

	await UserProfiles.update(user.id, {
		email: ps.email,
		emailVerified: false,
		emailVerifyCode: null,
	});

	const iObj = await Users.pack(user.id, user, {
		detail: true,
		includeSecrets: true,
	});

	// Publish meUpdated event
	publishMainStream(user.id, "meUpdated", iObj);

	if (ps.email != null) {
		const code = rndstr("a-z0-9", 16);

		await UserProfiles.update(user.id, {
			emailVerifyCode: code,
		});

		const link = `${config.url}/verify-email/${code}`;

		sendEmail(
			ps.email,
			"Email verification",
			`To verify email, please click this link:<br><a href="${link}">${link}</a>`,
			`To verify email, please click this link: ${link}`,
		);
	}

	return iObj;
});
