import { Summary } from 'prom-client';
import { createMySQLDuplicateKeyUpdate } from '../util/on-duplicate-key-update';

const Media = require('@cytube/mediaquery/lib/media');
const LOGGER = require('@calzoneman/jsli')('metadata-cache');

// TODO: these fullname-vs-shortcode hacks really need to be abolished
function mediaquery2cytube(type) {
    switch (type) {
        case 'youtube':
            return 'yt';
        case 'bitchute':
            return 'bc';
        default:
            throw new Error(`mediaquery2cytube: no mapping for ${type}`);
    }
}

function cytube2mediaquery(type) {
    switch (type) {
        case 'yt':
            return 'youtube';
        case 'bc':
            return 'bitchute';
        default:
            throw new Error(`cytube2mediaquery: no mapping for ${type}`);
    }
}

const cachedResultAge = new Summary({
    name: 'cytube_media_cache_result_age_seconds',
    help: 'Age (in seconds) of cached record',
    labelNames: ['source']
});

class MetadataCacheDB {
    constructor(db) {
        this.db = db;
    }

    async put(media) {
        media = new Media(media);
        media.type = mediaquery2cytube(media.type);
        return this.db.runTransaction(async tx => {
            let insert = tx.table('media_metadata_cache')
                .insert({
                    id: media.id,
                    type: media.type,
                    metadata: JSON.stringify(media),
                    updated_at: tx.raw('CURRENT_TIMESTAMP')
                });
            let update = tx.raw(createMySQLDuplicateKeyUpdate(
                ['metadata', 'updated_at']
            ));

            return tx.raw(insert.toString() + update.toString());
        });
    }

    async get(id, type) {
        return this.db.runTransaction(async tx => {
            let row = await tx.table('media_metadata_cache')
                .where({ id, type })
                .first();

            if (row === undefined || row === null) {
                return null;
            }

            let age = 0;
            try {
                age = (Date.now() - row.updated_at.getTime())/1000;
                if (age > 0) {
                    cachedResultAge.labels(type).observe(age);
                }
            } catch (error) {
                LOGGER.error('Failed to record cachedResultAge metric: %s', error.stack);
            }

            let metadata = JSON.parse(row.metadata);
            metadata.type = cytube2mediaquery(metadata.type);
            metadata.meta.cacheAge = age;
            return new Media(metadata);
        });
    }
}

export { MetadataCacheDB };
