"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UserService = void 0;
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
const bcrypt_1 = __importDefault(require("bcrypt"));
const uuid_1 = require("uuid");
const database_1 = require("../application/database");
const response_error_1 = require("../error/response-error");
const user_model_1 = require("../model/user-model");
const validation_1 = require("../validation/validation");
const user_validation_1 = require("../validation/user-validation");
class UserService {
    static create(request) {
        return __awaiter(this, void 0, void 0, function* () {
            // Validate the create request
            const createRequest = validation_1.Validation.validate(user_validation_1.UserValidation.CREATE, request);
            // Check if the email already exists
            const existingUser = yield database_1.db.queryOne('SELECT id FROM user WHERE email = ? LIMIT 1', [
                createRequest.email,
            ]);
            if (existingUser) {
                throw new response_error_1.ResponseError(400, 'Email sudah terdaftar');
            }
            // Hash the password before storing it
            const hashedPassword = yield bcrypt_1.default.hash(createRequest.password, 10);
            // Generate a new UUID for the user ID
            const userId = (0, uuid_1.v4)();
            // Insert the new user into the database
            yield database_1.db.query('INSERT INTO user (id, full_name, email, whatsapp_number, password, role) VALUES (?, ?, ?, ?, ?, ?)', [
                userId,
                createRequest.full_name,
                createRequest.email,
                createRequest.whatsapp_number,
                hashedPassword,
                createRequest.role,
            ]);
            // Retrieve the newly created user by the email
            const user = yield database_1.db.queryOne('SELECT * FROM user WHERE id = ? LIMIT 1', [userId]);
            if (!user) {
                throw new response_error_1.ResponseError(500, 'Gagal melakukan registrasi user');
            }
            return (0, user_model_1.toUserResponse)(user);
        });
    }
    static getAll(queryParams) {
        return __awaiter(this, void 0, void 0, function* () {
            // Validate the query params
            const queryRequest = validation_1.Validation.validate(user_validation_1.UserValidation.QUERY, queryParams);
            // Calculate the skip value
            const skip = (queryRequest.page - 1) * queryRequest.limit;
            // Create the WHERE clause
            let filterQuery = 'WHERE 1 = 1';
            const filterParams = [];
            if (queryRequest.full_name) {
                filterQuery += ' AND full_name LIKE ?';
                filterParams.push(`%${queryRequest.full_name}%`);
            }
            if (queryRequest.email) {
                filterQuery += ' AND email LIKE ?';
                filterParams.push(`%${queryRequest.email}%`);
            }
            if (queryRequest.whatsapp_number) {
                filterQuery += ' AND whatsapp_number LIKE ?';
                filterParams.push(`%${queryRequest.whatsapp_number}%`);
            }
            if (queryRequest.role) {
                filterQuery += ' AND role = ?';
                filterParams.push(queryRequest.role);
            }
            // Create the ORDER BY clause
            const sortField = queryRequest.sort || 'created_at';
            const sortOrder = queryRequest.order || 'desc';
            // Execute the query
            const users = yield database_1.db.query(`SELECT * FROM user ${filterQuery} ORDER BY ${sortField} ${sortOrder} LIMIT ? OFFSET ?`, [...filterParams, queryRequest.limit, skip]);
            // Get the total count
            const count = yield database_1.db.queryOne(`SELECT COUNT(*) AS total FROM user ${filterQuery}`, filterParams);
            if (!count) {
                throw new response_error_1.ResponseError(500, 'Failed to get total count');
            }
            // Return the pageable response
            return {
                data: users.map(user_model_1.toUserResponse),
                pagination: {
                    total: count.total,
                    current_page: queryRequest.page,
                    total_pages: Math.ceil(count.total / queryRequest.limit),
                    limit: queryRequest.limit,
                },
            };
        });
    }
    static get(id) {
        return __awaiter(this, void 0, void 0, function* () {
            // Execute the query
            const user = yield database_1.db.queryOne('SELECT * FROM user WHERE id = ? LIMIT 1', [id]);
            if (!user) {
                throw new response_error_1.ResponseError(404, 'User tidak ditemukan');
            }
            return (0, user_model_1.toUserResponse)(user);
        });
    }
    static updateCurrent(user, request) {
        return __awaiter(this, void 0, void 0, function* () {
            // Validate the update request
            const updateRequest = validation_1.Validation.validate(user_validation_1.UserValidation.UPDATE_CURRENT, request);
            // Check if the email already exists
            if (updateRequest.email) {
                const existingUser = yield database_1.db.queryOne('SELECT id FROM user WHERE email = ? LIMIT 1', [
                    updateRequest.email,
                ]);
                if (existingUser && existingUser.id !== user.id) {
                    throw new response_error_1.ResponseError(400, 'Email sudah terdaftar');
                }
            }
            // Initialize the query parameters
            const setClauses = [];
            const setParams = [];
            // Build the SET clause
            if (updateRequest.full_name) {
                setClauses.push('full_name = ?');
                setParams.push(updateRequest.full_name);
            }
            if (updateRequest.email) {
                setClauses.push('email = ?');
                setParams.push(updateRequest.email);
            }
            if (updateRequest.whatsapp_number) {
                setClauses.push('whatsapp_number = ?');
                setParams.push(updateRequest.whatsapp_number);
            }
            // Update the user in the database
            yield database_1.db.query(`UPDATE user SET ${setClauses.join(', ')} WHERE id = ?`, [...setParams, user.id]);
            // Retrieve the updated user
            const updatedUser = yield database_1.db.queryOne('SELECT * FROM user WHERE id = ? LIMIT 1', [user.id]);
            if (!updatedUser) {
                throw new response_error_1.ResponseError(500, 'Failed to update user');
            }
            // Generate a new JWT token
            const token = jsonwebtoken_1.default.sign({
                id: updatedUser.id,
                email: updatedUser.email,
                full_name: updatedUser.full_name,
                whatsapp_number: updatedUser.whatsapp_number,
                role: updatedUser.role,
            }, String(process.env.JWT_SECRET), {
                expiresIn: '24h',
            });
            // Format the user response
            const response = (0, user_model_1.toUserResponse)(updatedUser);
            response.token = token;
            return response;
        });
    }
    static updateCurrentPassword(user, request) {
        return __awaiter(this, void 0, void 0, function* () {
            // Validate the update password request
            const updatePasswordRequest = validation_1.Validation.validate(user_validation_1.UserValidation.UPDATE_PASSWORD, request);
            // Retrieve the old password
            const oldUserPassword = yield database_1.db.queryOne('SELECT password FROM user WHERE id = ? LIMIT 1', [
                user.id,
            ]);
            if (!oldUserPassword) {
                throw new response_error_1.ResponseError(404, 'User tidak ditemukan');
            }
            // Compare the old password
            const passwordMatch = yield bcrypt_1.default.compare(updatePasswordRequest.old_password, oldUserPassword.password);
            if (!passwordMatch) {
                throw new response_error_1.ResponseError(400, 'Password lama salah');
            }
            // Hash the new password
            const hashedPassword = yield bcrypt_1.default.hash(updatePasswordRequest.new_password, 10);
            // Update the password in the database
            yield database_1.db.query('UPDATE user SET password = ? WHERE id = ?', [hashedPassword, user.id]);
            // Retrieve the updated user
            const updatedUser = yield database_1.db.queryOne('SELECT * FROM user WHERE id = ? LIMIT 1', [user.id]);
            if (!updatedUser) {
                throw new response_error_1.ResponseError(500, 'Failed to update password');
            }
            return (0, user_model_1.toUserResponse)(updatedUser);
        });
    }
    static update(id, request) {
        return __awaiter(this, void 0, void 0, function* () {
            // Validate the update request
            const updateRequest = validation_1.Validation.validate(user_validation_1.UserValidation.UPDATE, request);
            // Check if the email already exists
            if (updateRequest.email) {
                const existingUser = yield database_1.db.queryOne('SELECT id FROM user WHERE email = ? LIMIT 1', [
                    updateRequest.email,
                ]);
                if (existingUser && existingUser.id !== id) {
                    throw new response_error_1.ResponseError(400, 'Email sudah terdaftar');
                }
            }
            // Initialize the query parameters
            const setClauses = [];
            const setParams = [];
            // Build the SET clause
            if (updateRequest.full_name) {
                setClauses.push('full_name = ?');
                setParams.push(updateRequest.full_name);
            }
            if (updateRequest.email) {
                setClauses.push('email = ?');
                setParams.push(updateRequest.email);
            }
            if (updateRequest.whatsapp_number) {
                setClauses.push('whatsapp_number = ?');
                setParams.push(updateRequest.whatsapp_number);
            }
            if (updateRequest.role) {
                setClauses.push('role = ?');
                setParams.push(updateRequest.role);
            }
            // Add the ID parameter
            setParams.push(id);
            // Execute the query
            yield database_1.db.query(`UPDATE user SET ${setClauses.join(', ')} WHERE id = ?`, setParams);
            // Retrieve the updated user
            const updatedUser = yield database_1.db.queryOne('SELECT * FROM user WHERE id = ? LIMIT 1', [id]);
            if (!updatedUser) {
                throw new response_error_1.ResponseError(500, 'Failed to update user');
            }
            return (0, user_model_1.toUserResponse)(updatedUser);
        });
    }
    static delete(id) {
        return __awaiter(this, void 0, void 0, function* () {
            // Retrieve the user to be deleted
            const user = yield database_1.db.queryOne('SELECT * FROM user WHERE id = ? LIMIT 1', [id]);
            if (!user) {
                throw new response_error_1.ResponseError(404, 'User tidak ditemukan');
            }
            // Delete the user from the database
            yield database_1.db.query('DELETE FROM user WHERE id = ?', [id]);
            return (0, user_model_1.toUserResponse)(user);
        });
    }
    static upgradeToMitra(id) {
        return __awaiter(this, void 0, void 0, function* () {
            // Retrieve the user to be upgraded
            const user = yield database_1.db.queryOne('SELECT * FROM user WHERE id = ? LIMIT 1', [id]);
            if (!user) {
                throw new response_error_1.ResponseError(404, 'User tidak ditemukan');
            }
            if (user.role !== 'USER') {
                throw new response_error_1.ResponseError(400, 'User sudah menjadi mitra');
            }
            // Upgrade the user to MITRA
            yield database_1.db.query('UPDATE user SET role = ? WHERE id = ?', ['MITRA', id]);
            // Retrieve the updated user
            const updatedUser = yield database_1.db.queryOne('SELECT * FROM user WHERE id = ? LIMIT 1', [id]);
            if (!updatedUser) {
                throw new response_error_1.ResponseError(500, 'Failed to upgrade user');
            }
            // Generate a new JWT token
            const token = jsonwebtoken_1.default.sign({
                id: updatedUser.id,
                email: updatedUser.email,
                full_name: updatedUser.full_name,
                whatsapp_number: updatedUser.whatsapp_number,
                role: updatedUser.role,
            }, String(process.env.JWT_SECRET), {
                expiresIn: '24h',
            });
            // Format the user response
            const response = (0, user_model_1.toUserResponse)(updatedUser);
            response.token = token;
            return response;
        });
    }
}
exports.UserService = UserService;
