import jwt from "jsonwebtoken";
import bcrypt from "bcryptjs";
import HttpError from "@/helpers/http-error";
import { Op } from "sequelize";
import { User } from "@/models/user";
import { v4 as uuidv4 } from "uuid";
import { z } from "zod";

export const Register = async (req, res, next) => {
    try {
        const validator = z.object({
            email: z
                .string({ required_error: "missing required field: email" })
                .email("invalid email"),
            username: z
                .string({ required_error: "missing required field: username" })
                .min(1, "username must be provided"),
            password: z
                .string({ required_error: "missing required field: password" })
                .min(1, "password must be provided"),
            role: z.enum(["admin", "staff"], {
                required_error: "missing required field: role",
            }),
        });

        const body = validator.parse(req.body);
        const hashedPassword = await bcrypt.hash(
            body.password,
            await bcrypt.genSalt(10),
        );

        const user = (
            await User.create({
                ...body,
                id: uuidv4(),
                password: hashedPassword,
            })
        )?.get({ plain: true });

        const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET_KEY);

        delete user["password"];

        res.status(200).json({
            success: true,
            meta: { token },
            data: user,
        });
    } catch (err) {
        next(err);
    }
};

export const Login = async (req, res, next) => {
    try {
        const validator = z.object({
            username: z
                .string({ required_error: "missing required field: username" })
                .min(1, "username must be provided"),
            password: z
                .string({ required_error: "missing required field: password" })
                .min(1, "password must be provided"),
        });

        const body = validator.parse(req.body);
        const user = (
            await User.findOne({
                where: {
                    [Op.or]: [
                        { username: body.username },
                        { email: body.username },
                    ],
                },
            })
        )?.get({ plain: true });

        if (!user || !(await bcrypt.compare(body.password, user.password))) {
            throw new HttpError(401, "invalid username or password");
        }

        const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET_KEY);

        delete user["password"];

        res.status(200).json({
            success: true,
            meta: { token },
            data: user,
        });
    } catch (err) {
        next(err);
    }
};
