import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Order, { OrderType } from 'App/Models/Order'
import PaginationService from 'App/Services/PaginationService'
import { schema } from '@ioc:Adonis/Core/Validator'
import { BadRequestException } from 'App/Exceptions/Common'
import Series from 'App/Models/Series'
import Episode from 'App/Models/Episode'
import UserBalanceService from 'App/Services/UserBalanceService'
import Decimal from 'decimal.js'
import BalanceRecord, { BalanceRecordType } from 'App/Models/BalanceRecord'

export default class OrdersController {
    private paginationService = new PaginationService(Order)
    public async index({ request, auth }: HttpContextContract) {
        const page = await this.paginationService.paginate({
            ...request.all(),
            userId: auth.user!.id
        })
        const seriesIds = new Set(
            page
                .all()
                .map((record) => record.seriesId)
                .filter((id) => !!id)
        )
        const series = await Series.findMany(Array.from(seriesIds))
        const episodeIds = new Set(
            page
                .all()
                .map((record) => record.episodeId)
                .filter((id) => !!id)
        )
        const episodes = await Episode.findMany(Array.from(episodeIds))
        page.all().forEach((record) => {
            if (record.seriesId) {
                record.series = series.find((s) => s.id === record.seriesId)
            }
            if (record.episodeId) {
                record.episode = episodes.find((e) => e.id === record.episodeId)
            }
        })
        return page
    }

    public async store({ request, auth }: HttpContextContract) {
        const user = auth.user!
        const data = await request.validate({
            schema: schema.create({
                seriesId: schema.number.optional(),
                episodeId: schema.number.optional()
            })
        })
        if (!data.seriesId && !data.episodeId) {
            throw new BadRequestException('seriesId or episodeId must be provided')
        }

        const userBalance = await UserBalanceService.getBalance(user.id)
        const order = new Order()
        order.userId = user.id

        if (data.seriesId) {
            const series = await Series.findOrFail(data.seriesId)
            if (series.price.comparedTo(userBalance.balance) > 0) {
                throw new Error('not enough balance')
            }
            order.price = series.price
            order.type = OrderType.Series
            order.seriesId = data.seriesId
        } else {
            const episode = await Episode.findOrFail(data.episodeId)
            if (episode.price.comparedTo(userBalance.balance) > 0) {
                throw new Error('not enough balance')
            }
            order.price = episode.price
            order.type = OrderType.Episode
            order.seriesId = episode.seriesId
            order.episodeId = data.episodeId!
        }

        await UserBalanceService.modifiyBalance({
            userId: user.id,
            amount: order.price.negated(),
            type: BalanceRecordType.Purchase,
            seriesId: data.seriesId,
            episodeId: data.episodeId
        })

        return await order.save()
    }

    public async show({ params }: HttpContextContract) {
        return await Order.findOrFail(params.id)
    }

    public async update({ response }: HttpContextContract) {
        response.notImplemented()
    }

    public async destroy({ response }: HttpContextContract) {
        response.notImplemented()
    }
}
