const axios = require('axios');
const qs = require('qs');
const {
    KEYCLOAK_REALM,
    KEYCLOAK_ADMIN_URL,
    CLIENT_ID,
    CLIENT_SECRET
} = require('../../../config/keycloak.js');
const HttpException = require('../../utils/HttpException.js');
const bcrypt = require('bcrypt');
const prisma = require('../../prisma/PrismaClient.js');

const getAdminToken = async () => {
    const tokenParams = qs.stringify({
        grant_type: 'client_credentials',
        client_id: CLIENT_ID,
        client_secret: CLIENT_SECRET
    });

    const { data } = await axios.post(
        `${KEYCLOAK_ADMIN_URL}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/token`,
        tokenParams,
        {
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        }
    );

    return data.access_token;
};

const KeycloakRepository = {
    createUser: async (userData) => {
        const token = await getAdminToken();

        // Cek apakah username sudah terpakai
        const { data: usersByUsername } = await axios.get(
            `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users?username=${encodeURIComponent(userData.username)}`,
            { headers: { Authorization: `Bearer ${token}` } }
        );

        if (usersByUsername.length > 0) {
            throw new HttpException('Username already exists in Keycloak', 409);
        }

        // Cek apakah email sudah terpakai
        const { data: usersByEmail } = await axios.get(
            `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users?email=${encodeURIComponent(userData.email)}`,
            { headers: { Authorization: `Bearer ${token}` } }
        );

        if (usersByEmail.length > 0) {
            throw new HttpException('Email already exists in Keycloak', 409);
        }

        const response = await axios.post(
            `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users`,
            {
                username: userData.username,
                email: userData.email,
                firstName: userData.firstname,
                lastName: userData.lastname,
                enabled: true,
                credentials: [{
                    type: "password",
                    value: userData.password,
                    temporary: false
                }]
            },
            { headers: { Authorization: `Bearer ${token}` } }
        );

        return response.headers.location.split('/').pop();
    },

    assignAdminRole: async (userId) => {
        const token = await getAdminToken();

        // Get role sales
        const { data: roles } = await axios.get(
            `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/roles`,
            { headers: { Authorization: `Bearer ${token}` } }
        );

        const adminRole = roles.find(role => role.name === 'admin');
        if (!adminRole) throw new HttpException('Admin role not found in Keycloak', 500);

        // Assign role to user
        await axios.post(
            `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users/${userId}/role-mappings/realm`,
            [adminRole],
            { headers: { Authorization: `Bearer ${token}` } }
        );
    },

    updateUser: async (userId, updatedData) => {
        const token = await getAdminToken();

        await axios.put(
            `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users/${userId}`,
            {
                firstName: updatedData.firstname,
                lastName: updatedData.lastname,
                email: updatedData.email,
                credentials: updatedData.password ? [{
                    type: 'password',
                    value: updatedData.password,
                    temporary: false
                }] : undefined
            },
            { headers: { Authorization: `Bearer ${token}` } }
        );
    },

    deleteUser: async (userId) => {
        const token = await getAdminToken();

        await axios.delete(
            `${KEYCLOAK_ADMIN_URL}/admin/realms/${KEYCLOAK_REALM}/users/${userId}`,
            { headers: { Authorization: `Bearer ${token}` } }
        );
    }
};

const AdminRepository = {
    createUser: async (userId, userData) => {
        const hashedPassword = await bcrypt.hash(userData.password, 10);

        return prisma.user.create({
            data: {
                id: userId,
                username: userData.username,
                email: userData.email,
                firstname: userData.firstname,
                lastname: userData.lastname,
                password: hashedPassword,
                role: 'admin'
            }
        });
    },

    findAll: async ({ skip, take, where, orderBy }) => {
        return prisma.user.findMany({
            where: {
                ...where,
                role: 'admin'
            },
            skip,
            take,
            orderBy,
            select: {
                id: true,
                username: true,
                email: true,
                firstname: true,
                lastname: true,
                role: true,
                createdAt: true,
                updatedAt: true,
            },
        });
    },

    countAll: async (where) => {
        return prisma.user.count({
            where: {
                ...where,
                role: 'admin'
            }
        });
    },

    findById: async (id) => {
        return prisma.user.findFirst({
            where: {
                id,
                deletedAt: null
            },
            select: {
                id: true,
                username: true,
                email: true,
                firstname: true,
                lastname: true,
                createdAt: true,
                updatedAt: true,
            }
        });
    },

    updateUser: async (id, updatedData) => {
        const updatePayload = {
            email: updatedData.email,
            firstname: updatedData.firstname,
            lastname: updatedData.lastname
        };

        if (updatedData.password) {
            updatePayload.password = await bcrypt.hash(updatedData.password, 10);
        }

        return prisma.user.update({
            where: { id },
            data: updatePayload
        });
    },

    deleteUser: async (id) => {
        return prisma.user.update({
            where: { id },
            data: {
                deletedAt: new Date()
            }
        });
    }
};

module.exports = { KeycloakRepository, AdminRepository };