"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RoleService = void 0;
const api_locale_1 = require("@hed-hog/api-locale");
const api_pagination_1 = require("@hed-hog/api-pagination");
const api_prisma_1 = require("@hed-hog/api-prisma");
const common_1 = require("@nestjs/common");
const integration_developer_api_service_1 = require("../integration/services/integration-developer-api.service");
let RoleService = class RoleService {
    constructor(prismaService, paginationService, localeService, integrationApi) {
        this.prismaService = prismaService;
        this.paginationService = paginationService;
        this.localeService = localeService;
        this.integrationApi = integrationApi;
    }
    async updateUsers(roleId, { ids }) {
        await this.prismaService.role_user.deleteMany({
            where: {
                role_id: roleId,
            },
        });
        return this.prismaService.role_user.createMany({
            data: ids.map((userId) => ({
                role_id: roleId,
                user_id: userId,
            })),
            skipDuplicates: true,
        });
    }
    async updateScreens(roleId, data) {
        await this.prismaService.role_screen.deleteMany({
            where: {
                role_id: roleId,
            },
        });
        return this.prismaService.role_screen.createMany({
            data: data.ids.map((screenId) => ({
                role_id: roleId,
                screen_id: screenId,
            })),
            skipDuplicates: true,
        });
    }
    async updateRoutes(roleId, data) {
        await this.prismaService.role_route.deleteMany({
            where: {
                role_id: roleId,
            },
        });
        return this.prismaService.role_route.createMany({
            data: data.ids.map((routeId) => ({
                role_id: roleId,
                route_id: routeId,
            })),
            skipDuplicates: true,
        });
    }
    async updateMenus(roleId, data) {
        await this.prismaService.role_menu.deleteMany({
            where: {
                role_id: roleId,
            },
        });
        return this.prismaService.role_menu.createMany({
            data: data.ids.map((menuId) => ({
                role_id: roleId,
                menu_id: menuId,
            })),
            skipDuplicates: true,
        });
    }
    async listUsers(roleId, paginationParams) {
        return this.paginationService.paginate(this.prismaService.user, paginationParams, {
            include: {
                role_user: {
                    where: {
                        role_id: roleId,
                    },
                    select: {
                        user_id: true,
                        role_id: true,
                    },
                },
            },
        });
    }
    async listMenus(locale, roleId, paginationParams) {
        return this.paginationService.paginate(this.prismaService.menu, paginationParams, {
            include: {
                menu_locale: {
                    where: {
                        locale: {
                            code: locale,
                        },
                    },
                    select: {
                        name: true,
                    },
                },
                role_menu: {
                    where: {
                        role_id: roleId,
                    },
                    select: {
                        menu_id: true,
                        role_id: true,
                    },
                },
            },
        }, 'menu_locale');
    }
    async listRoutes(roleId, paginationParams, search, searchType, method) {
        const whereClause = {};
        // Filtro de busca por URL
        if (search) {
            if (searchType === 'startsWith') {
                whereClause.url = {
                    startsWith: search,
                };
            }
            else if (searchType === 'endsWith') {
                whereClause.url = {
                    endsWith: search,
                };
            }
            else {
                // contains (padrão)
                whereClause.url = {
                    contains: search,
                };
            }
        }
        // Filtro por método HTTP
        if (method && method !== 'all') {
            whereClause.method = method;
        }
        return this.paginationService.paginate(this.prismaService.route, paginationParams, {
            where: whereClause,
            include: {
                role_route: {
                    where: {
                        role_id: roleId,
                    },
                    select: {
                        route_id: true,
                        role_id: true,
                    },
                },
            },
        });
    }
    async listScreens(locale, roleId, paginationParams) {
        return this.paginationService.paginate(this.prismaService.screen, paginationParams, {
            include: {
                screen_locale: {
                    where: {
                        locale: {
                            code: locale,
                        },
                    },
                    select: {
                        name: true,
                    },
                },
                role_screen: {
                    where: {
                        role_id: roleId,
                    },
                    select: {
                        screen_id: true,
                        role_id: true,
                    },
                },
            },
        }, 'screen_locale');
    }
    async list(paginationParams, locale) {
        var _a;
        const localeRecord = await this.localeService.getByCode(locale);
        if (!localeRecord) {
            throw new Error((0, api_locale_1.getLocaleText)('localeNotFound', locale, `Locale ${locale} not found`).replace('{{locale}}', locale));
        }
        const localeId = localeRecord.id;
        const searchRaw = ((_a = paginationParams.search) !== null && _a !== void 0 ? _a : '').toString().trim();
        const hasSearch = searchRaw.length > 0;
        const like = `%${searchRaw.toLowerCase()}%`;
        const rowsQuery = hasSearch
            ? this.prismaService.$queryRaw `
      SELECT
        f.id AS role_id,
        f.slug,
        fl.locale_id,
        fl.name,
        fl.description,
        (
          SELECT json_agg(json_build_object('code', l.code, 'name', l.name))
          FROM role_locale fl2
          JOIN locale l ON l.id = fl2.locale_id
          WHERE fl2.role_id = f.id 
            AND l.enabled = true
            AND fl2.name IS NOT NULL 
            AND fl2.name != ''
            AND fl2.description IS NOT NULL 
            AND fl2.description != ''
        ) AS available_locales,
        (
          SELECT COUNT(*)::int
          FROM role_user ru
          WHERE ru.role_id = f.id
        ) AS user_count,
        (
          SELECT COUNT(*)::int
          FROM role_menu rm
          WHERE rm.role_id = f.id
        ) AS menu_count,
        (
          SELECT COUNT(*)::int
          FROM role_route rr
          WHERE rr.role_id = f.id
        ) AS route_count
      FROM role AS f
      JOIN role_locale AS fl
        ON fl.role_id = f.id
      WHERE fl.locale_id = ${localeId}
        AND (
        LOWER(fl.name) LIKE ${like}
        OR LOWER(fl.description) LIKE ${like}
        )
      ORDER BY f.id DESC
      LIMIT ${paginationParams.take}
      OFFSET ${paginationParams.skip}
      `
            : this.prismaService.$queryRaw `
      SELECT
        f.id AS role_id,
        f.slug,
        fl.locale_id,
        fl.name,
        fl.description,
        (
          SELECT json_agg(json_build_object('code', l.code, 'name', l.name))
          FROM role_locale fl2
          JOIN locale l ON l.id = fl2.locale_id
          WHERE fl2.role_id = f.id 
            AND l.enabled = true
            AND fl2.name IS NOT NULL 
            AND fl2.name != ''
            AND fl2.description IS NOT NULL 
            AND fl2.description != ''
        ) AS available_locales,
        (
          SELECT COUNT(*)::int
          FROM role_user ru
          WHERE ru.role_id = f.id
        ) AS user_count,
        (
          SELECT COUNT(*)::int
          FROM role_menu rm
          WHERE rm.role_id = f.id
        ) AS menu_count,
        (
          SELECT COUNT(*)::int
          FROM role_route rr
          WHERE rr.role_id = f.id
        ) AS route_count
      FROM role AS f
      JOIN role_locale AS fl
        ON fl.role_id = f.id
      WHERE fl.locale_id = ${localeId}
      ORDER BY f.id DESC
      LIMIT ${paginationParams.take}
      OFFSET ${paginationParams.skip}
      `;
        const countQuery = this.prismaService.role.count({
            where: Object.assign({ role_locale: { some: { locale_id: localeId } } }, (hasSearch && {
                OR: [
                    { role_locale: { some: { locale_id: localeId, name: { contains: searchRaw, mode: 'insensitive' } } } },
                    { role_locale: { some: { locale_id: localeId, description: { contains: searchRaw, mode: 'insensitive' } } } },
                ],
            })),
        });
        const [rows, total] = await Promise.all([rowsQuery, countQuery]);
        const mappedRows = rows.map((row) => (Object.assign(Object.assign({}, row), { available_locales: row.available_locales || [] })));
        const pageSize = paginationParams.take;
        const page = Math.floor(paginationParams.skip / pageSize) + 1;
        const lastPage = Math.max(1, Math.ceil(total / pageSize));
        const prev = page > 1 ? page - 1 : null;
        const next = page < lastPage ? page + 1 : null;
        return {
            data: mappedRows,
            total,
            page,
            pageSize,
            prev,
            next,
            lastPage,
        };
    }
    async get(roleId) {
        const role = await this.prismaService.role.findUnique({
            where: { id: roleId },
            include: {
                role_locale: {
                    include: {
                        locale: {
                            select: { code: true },
                        },
                    },
                },
            },
        });
        if (!role) {
            throw new common_1.NotFoundException(`Role with ID ${roleId} not found`);
        }
        const localeData = role.role_locale.reduce((acc, item) => {
            const localeCode = item.locale.code;
            acc[localeCode] = {
                name: item.name,
                description: item.description,
            };
            return acc;
        }, {});
        return Object.assign(Object.assign({}, role), { locale: localeData });
    }
    async create(body) {
        const { locale, slug } = body;
        const role = await this.prismaService.role.create({
            data: { slug },
        });
        if (locale) {
            await Promise.all(Object.entries(locale).map(async ([localeCode, localeData]) => {
                const localeRecord = await this.localeService.getByCode(localeCode);
                await this.prismaService.role_locale.create({
                    data: {
                        role_id: role.id,
                        locale_id: localeRecord.id,
                        name: localeData.name,
                        description: localeData.description,
                    },
                });
            }));
        }
        const result = await this.get(role.id);
        await this.integrationApi.publishEvent({
            eventName: 'core.role.created',
            sourceModule: 'core',
            aggregateType: 'role',
            aggregateId: String(role.id),
            payload: { id: role.id, slug },
        }).catch(() => null);
        return result;
    }
    async update(id, body, localeRequest) {
        const roleExists = await this.prismaService.role.findUnique({
            where: { id },
        });
        if (!roleExists) {
            throw new common_1.NotFoundException((0, api_locale_1.getLocaleText)('itemNotFound', localeRequest, `Role with ID ${id} not found`).replace('{{item}}', 'Role'));
        }
        const { locale } = body;
        if (locale) {
            await Promise.all(Object.entries(locale).map(async ([localeCode, localeData]) => {
                const localeRecord = await this.localeService.getByCode(localeCode);
                const existing = await this.prismaService.role_locale.findFirst({
                    where: {
                        role_id: id,
                        locale_id: localeRecord.id,
                    },
                });
                if (existing) {
                    await this.prismaService.role_locale.update({
                        where: { id: existing.id },
                        data: {
                            name: localeData.name,
                            description: localeData.description,
                        },
                    });
                }
                else {
                    await this.prismaService.role_locale.create({
                        data: {
                            role_id: id,
                            locale_id: localeRecord.id,
                            name: localeData.name,
                            description: localeData.description,
                        },
                    });
                }
            }));
        }
        const result = await this.get(id);
        await this.integrationApi.publishEvent({
            eventName: 'core.role.updated',
            sourceModule: 'core',
            aggregateType: 'role',
            aggregateId: String(id),
            payload: { id, slug: body.slug },
        }).catch(() => null);
        return result;
    }
    async delete({ ids }, localeRequest = 'en') {
        if (ids == undefined || ids == null) {
            throw new common_1.BadRequestException((0, api_locale_1.getLocaleText)('deleteItemsRequired', localeRequest, 'You must select at least one permission to delete.'));
        }
        const existingRoles = await this.prismaService.role.findMany({
            where: {
                id: {
                    in: ids,
                },
            },
        });
        if (existingRoles.length !== ids.length) {
            const existingIds = existingRoles.map((role) => role.id);
            const missingIds = ids.filter((id) => !existingIds.includes(id));
            throw new common_1.NotFoundException((0, api_locale_1.getLocaleText)('itemsNotFound', localeRequest, `Roles with IDs ${missingIds.join(', ')} not found`).replace('{{items}}', 'Roles'));
        }
        const result = await this.prismaService.role.deleteMany({
            where: {
                id: {
                    in: ids,
                },
            },
        });
        await this.integrationApi.publishEvent({
            eventName: 'core.role.deleted',
            sourceModule: 'core',
            aggregateType: 'role',
            aggregateId: ids.join(','),
            payload: { ids },
        }).catch(() => null);
        return result;
    }
};
exports.RoleService = RoleService;
exports.RoleService = RoleService = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, common_1.Inject)((0, common_1.forwardRef)(() => api_prisma_1.PrismaService))),
    __param(1, (0, common_1.Inject)((0, common_1.forwardRef)(() => api_pagination_1.PaginationService))),
    __param(2, (0, common_1.Inject)((0, common_1.forwardRef)(() => api_locale_1.LocaleService))),
    __param(3, (0, common_1.Inject)((0, common_1.forwardRef)(() => integration_developer_api_service_1.IntegrationDeveloperApiService))),
    __metadata("design:paramtypes", [api_prisma_1.PrismaService,
        api_pagination_1.PaginationService,
        api_locale_1.LocaleService,
        integration_developer_api_service_1.IntegrationDeveloperApiService])
], RoleService);
//# sourceMappingURL=role.service.js.map