// podman exec -it tethys_backend_1 node ace validate:checksum
// sudo crontab -u www-data -e
// */5  *  *  *  * podman exec -u www-data tethys_backend_1 node ace validate:checksum
import { XMLBuilder } from 'xmlbuilder2/lib/interfaces.js';
import { create } from 'xmlbuilder2';
import Dataset from '#models/dataset';
import XmlModel from '#app/Library/XmlModel';
import { readFileSync } from 'fs';
import SaxonJS from 'saxon-js';
import { Client } from '@opensearch-project/opensearch';
import { getDomain } from '#app/utils/utility-functions';
import { BaseCommand, flags } from '@adonisjs/core/ace';
import { CommandOptions } from '@adonisjs/core/types/ace';
import env from '#start/env';
// import db from '@adonisjs/lucid/services/db';
// import { default as Dataset } from '#models/dataset';
import logger from '@adonisjs/core/services/logger';


const opensearchNode = env.get('OPENSEARCH_HOST', 'localhost');
const client = new Client({ node: `${opensearchNode}` }); // replace with your OpenSearch endpoint

export default class IndexDatasets extends BaseCommand {
    static commandName = 'index:datasets';
    static description = 'Index datasets based on publish_id';

    public static needsApplication = true;

    @flags.number({ alias: 'p' })
    public publish_id: number;

    public static options: CommandOptions = {
        startApp: true,       
        staysAlive: false,
    };


    async run() {
        logger.debug('Hello world!');
        // const { default: Dataset } = await import('#models/dataset');
        // const datasets = await Dataset.query().where('server_state', 'published').exec(); //this.getDatasets();
        const datasets = await this.getDatasets();
        const proc = readFileSync('public/assets2/solr.sef.json');
        const index_name = 'tethys-records';

        for (var dataset of datasets) {
            // Logger.info(`File publish_id ${dataset.publish_id}`);
            // const jsonString = await this.getJsonString(dataset, proc);
            // console.log(jsonString);
            await this.indexDocument(dataset, index_name, proc);
        }
    }

    private async getDatasets(): Promise<any[]> {
        // const { default: Dataset } = await import('#models/dataset');
        // const Dataset = (await import('#models/dataset')).default
        //    const Dataset = (
        //         await this.app.container.make('#models/dataset')
        //       ).default;
        // const query: ModelQueryBuilder<Dataset, any> = db.from(Dataset);
        const query = Dataset.query().preload('xmlCache').where('server_state', 'published');
        if (this.publish_id) {
            query.where('publish_id', this.publish_id);
        }
        return await query.exec();
    }

    private async indexDocument(dataset: Dataset, index_name: string, proc: Buffer): Promise<void> {
        try {
            const doc = await this.getJsonString(dataset, proc);

            let document = JSON.parse(doc);
            await client.index({
                id: dataset.publish_id?.toString(),
                index: index_name,
                body: document,
                refresh: true,
            });
            logger.info(`dataset with publish_id ${dataset.publish_id} successfully indexed`);
        } catch (error) {
            logger.error(`An error occurred while indexing dataset with publish_id ${dataset.publish_id}.`);
        }
    }

    private async getJsonString(dataset: Dataset, proc: Buffer) {
        let xml = create({ version: '1.0', encoding: 'UTF-8', standalone: true }, '<root></root>');
        const datasetNode = xml.root().ele('Dataset');
        await this.createXmlRecord(dataset, datasetNode);
        const xmlString = xml.end({ prettyPrint: false });

        try {
            const result = await SaxonJS.transform({
                stylesheetText: proc,
                destination: 'serialized',
                sourceText: xmlString,
            });
            return result.principalResult;
        } catch (error) {
            logger.error(`An error occurred while creating the user, error: ${error.message},`);
            return '';
        }
    }

    private async createXmlRecord(dataset: Dataset, datasetNode: XMLBuilder): Promise<void> {
        const domNode = await this.getDatasetXmlDomNode(dataset);
        if (domNode) {
            dataset.publish_id && this.addLandingPageAttribute(domNode, dataset.publish_id.toString());
            this.addSpecInformation(domNode, 'data-type:' + dataset.type);
            datasetNode.import(domNode);
        }
    }

    private async getDatasetXmlDomNode(dataset: Dataset): Promise<XMLBuilder | null> {
        const xmlModel = new XmlModel(dataset);
        // xmlModel.setModel(dataset);
        xmlModel.excludeEmptyFields();
        xmlModel.caching = true;
        // const cache = dataset.xmlCache ? dataset.xmlCache : null;
        // dataset.load('xmlCache');
        if (dataset.xmlCache) {
            xmlModel.xmlCache = dataset.xmlCache;
        }

        // return cache.getDomDocument();
        const domDocument: XMLBuilder | null = await xmlModel.getDomDocument();
        return domDocument;
    }

    private addSpecInformation(domNode: XMLBuilder, information: string) {
        domNode.ele('SetSpec').att('Value', information);
    }

    private addLandingPageAttribute(domNode: XMLBuilder, dataid: string) {
        const baseDomain = process.env.OAI_BASE_DOMAIN || 'localhost';
        const url = 'https://' + getDomain(baseDomain) + '/dataset/' + dataid;
        // add attribute du dataset xml element
        domNode.att('landingpage', url);
    }
}
