import {
    Injectable,
    NotFoundException,
    ConflictException,
} from '@nestjs/common'
import { Prisma } from 'generated/prisma/client'
import { PrismaService } from 'src/prisma/prisma.service'
import { CreateBankDto, UpdateBankDto } from './dto/bank.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 BankService {
    constructor(private readonly prisma: PrismaService) {}

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

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

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

        const orderBy: Prisma.BankOrderByWithRelationInput = {}
        if (query.sort && allowedSortColumns.includes(query.sort)) {
            orderBy[query.sort] = query.sortOrder
        } else {
            orderBy.name = 'asc'
        }

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

        return new BootstrapTableResponseDto(total, rows)
    }

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

    async create(dto: CreateBankDto) {
        const existing = await this.prisma.bank.findUnique({
            where: { code: dto.code },
        })
        if (existing)
            throw new ConflictException(`Bank code "${dto.code}" already exists`)

        return this.prisma.bank.create({ data: dto })
    }

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

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

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

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