import { Injectable, NotFoundException, ConflictException } from '@nestjs/common'
import { Prisma } from 'generated/prisma/client'
import { PrismaService } from '../prisma/prisma.service'
import { CreateRoleDto } from './create-role.dto'
import { UpdateRoleDto } from './update-role.dto'
import { BootstrapTableRequestDto } from 'src/commons/dto/bootstrap-table-request.dto'
import { BootstrapTableResponseDto } from 'src/commons/dto/bootstrap-table-response.dto'
import { buildWhereClause } from 'src/commons/utils/prisma-query-builder'

@Injectable()
export class RoleService {
    constructor(private readonly prisma: PrismaService) {}

    async findAll(query: BootstrapTableRequestDto) {
        const allowedFilters = {
            code: 'string',
            name: 'string',
            accessAllBranch: 'enum',
        } as const

        const where = buildWhereClause(query, allowedFilters, ['code', 'name'])

        const allowedSortColumns = [
            'code',
            'name',
            'accessAllBranch',
            'createdAt',
        ]

        const orderBy: Prisma.RoleOrderByWithRelationInput = {}

        if (query.sort && allowedSortColumns.includes(query.sort)) {
            orderBy[query.sort] = query.sortOrder
        } else {
            orderBy.createdAt = 'desc'
        }

        const [total, rows] = await this.prisma.$transaction([
            this.prisma.role.count({ where }),
            this.prisma.role.findMany({
                where,
                skip: query.skip,
                take: query.take,
                orderBy,
            }),
        ])

        return new BootstrapTableResponseDto(total, rows)
    }

    async findOne(id: string) {
        const role = await this.prisma.role.findUnique({ where: { id } })
        if (!role) throw new NotFoundException(`Role with id ${id} not found`)
        return role
    }

    async create(dto: CreateRoleDto) {
        const existing = await this.prisma.role.findUnique({ where: { code: dto.code } })
        if (existing) {
            throw new ConflictException(`Role code "${dto.code}" already exists`)
        }
        return this.prisma.role.create({ data: dto })
    }

    async update(id: string, dto: UpdateRoleDto) {
        await this.findOne(id)

        if (dto.code) {
            const conflict = await this.prisma.role.findFirst({
                where: { code: dto.code, NOT: { id } },
            })
            if (conflict) {
                throw new ConflictException(`Role code "${dto.code}" already exists`)
            }
        }

        return this.prisma.role.update({ where: { id }, data: dto })
    }

    async remove(id: string) {
        await this.findOne(id)
        return this.prisma.role.delete({ where: { id } })
    }
}