import { LucidModel, ModelQueryBuilderContract } from '@ioc:Adonis/Lucid/Orm'

export default class PaginationService<T extends LucidModel> {
    protected model: T
    constructor(model: T) {
        this.model = model
    }
    public async paginate(
        query: any,
        injectQuery?: (q: ModelQueryBuilderContract<T, InstanceType<T>>) => void
    ) {
        let q = this.model.query()
        if (injectQuery) {
            injectQuery(q)
        }
        Object.keys(query).forEach((key) => {
            if (
                ['page', 'pageSize', 'order', 'preload'].includes(key) ||
                query[key] === undefined ||
                query[key] === null ||
                query[key] === ''
            ) {
                return
            }
            if (this.model.$hasColumn(key)) {
                const col = this.model.$getColumn(key)
                if (col?.meta?.type === 'boolean') {
                    q.where(key, query[key] === 'true' || query[key] === true)
                } else {
                    q.where(key, query[key])
                }
            }
        })
        let orders: { column: string; order: 'asc' | 'desc' }[] = []
        if (query.order) {
            query.order.split(';').forEach((e) => {
                let [column, order] = e.split(',')
                if (this.model.$hasColumn(column)) {
                    orders.push({ column, order: order || 'asc' })
                }
            })
        }
        if (orders.length === 0 && this.model.$hasColumn('createdAt')) {
            orders.push({ column: 'createdAt', order: 'desc' })
        }
        q.orderBy(orders)
        if (query.preload) {
            if (query.preload === 'true' || query.preload === true) {
                this.model.$relationsDefinitions.forEach((e) => {
                    q.preload(e.relationName as any)
                })
            } else {
                query.preload.split(',').forEach((e) => {
                    q.preload(e)
                })
            }
        }
        return await q.paginate(query.page || 1, query.pageSize || 20)
    }
}
