import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Episode from 'App/Models/Episode'
import PaginationService from 'App/Services/PaginationService'
import { schema } from '@ioc:Adonis/Core/Validator'
import Decimal from 'decimal.js'
import Order, { OrderType } from 'App/Models/Order'
import Drive from '@ioc:Adonis/Core/Drive'
import Membership from 'App/Models/Membership'

export default class EpisodesController {
    private paginationService = new PaginationService(Episode)
    public async index({ request }: HttpContextContract) {
        return await this.paginationService.paginate(request.all())
    }

    public async store({ request, bouncer }: HttpContextContract) {
        await bouncer.authorize('admin')
        const data: any = await request.validate({
            schema: schema.create({
                seriesId: schema.number(),
                title: schema.string.optional(),
                episodeNum: schema.number(),
                description: schema.string.optional(),
                cover: schema.string.optional(),
                video: schema.string.optional(),
                playCount: schema.number.optional(),
                price: schema.string.optional()
            })
        })
        if (data.price) {
            data.price = new Decimal(data.price)
        }
        return await Episode.create(data)
    }

    public async show({ params, auth }: HttpContextContract) {
        const episode = await Episode.findOrFail(params.id)

        if (episode.price.eq(0)) {
            episode.purchased = true
        } else if (auth.user) {
            const member = await Membership.query()
                .where('userId', auth.user.id)
                .where('expireAt', '>', new Date())
                .first()
            if (member) {
                episode.purchased = true
            } else {
                let order = await Order.query()
                    .where('userId', auth.user.id)
                    .where('type', OrderType.Series)
                    .where('seriesId', episode.seriesId)
                    .first()
                if (!order) {
                    order = await Order.query()
                        .where('userId', auth.user.id)
                        .where('type', OrderType.Episode)
                        .where('episodeId', episode.id)
                        .first()
                }
                if (order) {
                    episode.purchased = true
                }
            }
        }
        if (episode.purchased) {
            let url = episode.video!
            if (/\.m3u8$/.test(url)) {
                episode.signedUrl = url
            } else {
                if (/^http/.test(url)) {
                    url = new URL(url).pathname
                }
                url = url.replace(/^\//, '')
                episode.signedUrl = await Drive.getSignedUrl(url.replace(/^\//, ''), {
                    expiresIn: '1h'
                })
            }
        }
        return episode
    }

    public async update({ request, params, bouncer }: HttpContextContract) {
        await bouncer.authorize('admin')
        const data: any = await request.validate({
            schema: schema.create({
                seriesId: schema.number.optional(),
                title: schema.string.optional(),
                episodeNum: schema.number.optional(),
                description: schema.string.optional(),
                cover: schema.string.optional(),
                video: schema.string.optional(),
                playCount: schema.number.optional(),
                price: schema.number.optional()
            })
        })
        if (data.price) {
            data.price = new Decimal(data.price)
        }
        const episode = await Episode.findOrFail(params.id)
        episode.merge(data)
        return await episode.save()
    }

    public async destroy({ params, bouncer }: HttpContextContract) {
        await bouncer.authorize('admin')
        const episode = await Episode.findOrFail(params.id)
        await episode.delete()
    }
}
