/* eslint-disable prefer-arrow-functions/prefer-arrow-functions */
import { Express } from 'express';
import { childLogger, Logger } from "@foxxmd/logging";
import bodyParser from "body-parser";
import ScrobbleSources from "../sources/ScrobbleSources.js";
import { nonEmptyBody } from "./middleware.js";
import { LFMEndpointNotifier } from "../sources/ingressNotifiers/LFMEndpointNotifier.js";
import { EndpointLastfmSource, playStateFromRequest, parseDisplayIdentifiersFromRequest } from "../sources/EndpointLastfmSource.js";
import { LastFMScrobbleRequestPayload } from "../common/vendor/LastfmApiClient.js";

export const setupLastfmEndpointRoutes = (app: Express, parentLogger: Logger, scrobbleSources: ScrobbleSources) => {

    const logger = childLogger(parentLogger, ['Ingress', 'LFM']);

    const nonEmptyCheck = nonEmptyBody(logger, 'LFM Endpoint');

    const webhookIngress = new LFMEndpointNotifier(logger);
    app.use(/(\/api\/lastfm(?!\/callback))|(\/2.0\/?)$/,
        async function (req, res, next) {
            // track request before parsing body to ensure we at least log that something is happening
            // (in the event body parsing does not work or request is not POST/PATCH)
            webhookIngress.trackIngress(req, true);
            if (req.method !== 'POST') {
                return res.sendStatus(405);
            }
            next();
        },
        bodyParser.urlencoded({ extended: true }), 
        nonEmptyCheck, async function (req, res) {
            webhookIngress.trackIngress(req, false);

            const sources = scrobbleSources.getByType('endpointlfm') as EndpointLastfmSource[];
            if (sources.length === 0) {
                logger.warn('Received Lastfm endpoint payload but no Lastfm endpoint sources are configured');
            }

            const validSources = sources.filter(x => x.matchRequest(req));
            if (validSources.length === 0) {
                const [slug] = parseDisplayIdentifiersFromRequest(req);
                logger.warn(`No Lastfm endpoint config matched => Slug: ${slug}`);
            }

            if(!('method' in req.body)) {
                return res.status(400).json({error: `Missing 'method' param`});
            }
            const method = (req.body as LastFMScrobbleRequestPayload).method;
            if(!['track.updateNowPlaying','track.scrobble'].includes(method)) {
                return res.status(400).json({error: `Unexpected 'method' param value '${method}', expected either 'track.updateNowPlaying' or 'track.scrobble'`});
            }

            res.sendStatus(200);

            const playerState = playStateFromRequest(req.body);

            for (const source of validSources) {
                await source.handle(playerState);
            }
        });
}

