#!/usr/bin/env node
// (C) 2021-2023 GoodData Corporation
const fs = require('fs');
const path = require('path');
const { createArrayCsvWriter: createCsvWriter } = require('csv-writer');
const crypto = require('crypto');

const basePath = '../../fixtures/ComplexModel';
const basePathSeedFiles = '../../fixtures/SingleInvoice';

const firstNames = fs
    .readFileSync(path.join(basePathSeedFiles, 'firstnames.txt'), 'utf8')
    .split('\n');
const lastNames = fs
    .readFileSync(path.join(basePathSeedFiles, 'surnames.txt'), 'utf8')
    .split('\n');

async function generateRows(names, attributeCount, factCount, numberOfRows) {
    const records = [];

    for (let i = 0; i < numberOfRows; i += 1) {
        const attributeValues = [];
        const factValues = [];
        for (let j = 0; j < attributeCount - 2; j += 1) {
            attributeValues.push(crypto.randomBytes(4).toString('hex'));
        }

        for (let j = 0; j < factCount; j += 1) {
            factValues.push(Math.floor(Math.random() * 1000));
        }

        records.push([
            names[i],
            names[Math.floor(Math.random() * names.length)],
            ...attributeValues,
            ...factValues,
            // eslint-disable-next-line no-mixed-operators
            new Date(new Date() - Math.random() * 1e12).toLocaleDateString(
                'en-US'
            )
        ]);
    }

    return records;
}

async function generateMainContentCsv(
    mainDataset,
    attributeCount,
    factCount,
    mainDatasetCount,
    subDatasetCount
) {
    const headerContent = [];
    const mainDatasetName = `m${mainDataset.toString().padStart(2, '0')}`;
    for (let j = 1; j <= attributeCount; j += 1) {
        if (j !== 1 && j <= subDatasetCount + 1) {
            const attributeName = `m${mainDataset
                .toString()
                .padStart(2, '0')}s${(j - 1)
                .toString()
                .padStart(2, '0')}.attr01`;
            headerContent.push(attributeName);
        } else if (
            j === subDatasetCount + 2 &&
            mainDataset !== mainDatasetCount
        ) {
            const attributeName = `m${(mainDataset + 1)
                .toString()
                .padStart(2, '0')}.attr01`;
            headerContent.push(attributeName);
        } else {
            const attributeName = `${mainDatasetName}.attr${j
                .toString()
                .padStart(2, '0')}`;
            headerContent.push(attributeName);
        }
    }

    for (let j = 1; j <= factCount; j += 1) {
        const factName = `${mainDatasetName}.fact${j
            .toString()
            .padStart(2, '0')}`;
        headerContent.push(factName);
    }

    const dateName = `${mainDatasetName}.date01`;
    headerContent.push(dateName);

    return headerContent;
}

async function generateSubContentCsv(
    mainDataset,
    subDataset,
    attributeCount,
    factCount
) {
    const headerContent = [];
    const subDatasetName = `m${mainDataset
        .toString()
        .padStart(2, '0')}s${subDataset.toString().padStart(2, '0')}`;
    for (let j = 1; j <= attributeCount; j += 1) {
        const attributeName = `${subDatasetName}.attr${j
            .toString()
            .padStart(2, '0')}`;
        headerContent.push(attributeName);
    }

    for (let j = 1; j <= factCount; j += 1) {
        const factName = `${subDatasetName}.fact${j
            .toString()
            .padStart(2, '0')}`;
        headerContent.push(factName);
    }

    const dateName = `${subDatasetName}.date01`;
    headerContent.push(dateName);

    return headerContent;
}

async function generateCsvForMainDataset(
    mainDatasetCount,
    subDatasetCount,
    mainAttributeCount,
    mainFactCount,
    numberOfRows
) {
    const names = [];
    Array(numberOfRows)
        .fill()
        // eslint-disable-next-line array-callback-return
        .map(() => {
            names.push(
                // eslint-disable-next-line prefer-template
                firstNames[Math.floor(Math.random() * firstNames.length)] +
                    ' ' +
                    lastNames[Math.floor(Math.random() * lastNames.length)]
            );
        });

    for (let i = 1; i <= mainDatasetCount; i += 1) {
        const mainDatasetName = `m${i.toString().padStart(2, '0')}`;

        fs.mkdirSync(basePath, { recursive: true });

        const csvWriter = createCsvWriter({
            // eslint-disable-next-line no-await-in-loop
            header: await generateMainContentCsv(
                i,
                mainAttributeCount,
                mainFactCount,
                mainDatasetCount,
                subDatasetCount
            ),
            path: `${basePath}/${mainDatasetName}.csv`
        });

        const records = generateRows(
            names,
            mainAttributeCount,
            mainFactCount,
            numberOfRows
        );

        csvWriter
            // eslint-disable-next-line no-await-in-loop
            .writeRecords(await records)
            .then(() => {
                // eslint-disable-next-line no-console
                console.log(`Generated ${mainDatasetName}`);
            })
            .catch((err) => {
                // eslint-disable-next-line no-console
                console.error(`Failed to write ${mainDatasetName}: ${err}`);
            });
    }
}

async function generateCsvForSubDataset(
    mainDatasetCount,
    subDatasetCount,
    subAttributeCount,
    subFactCount,
    numberOfRows
) {
    const names = [];
    Array(numberOfRows)
        .fill()
        // eslint-disable-next-line array-callback-return
        .map(() => {
            names.push(
                // eslint-disable-next-line prefer-template
                firstNames[Math.floor(Math.random() * firstNames.length)] +
                    ' ' +
                    lastNames[Math.floor(Math.random() * lastNames.length)]
            );
        });

    for (let i = 1; i <= mainDatasetCount; i += 1) {
        for (let j = 1; j <= subDatasetCount; j += 1) {
            const subDatasetName = `m${i.toString().padStart(2, '0')}s${j
                .toString()
                .padStart(2, '0')}`;

            fs.mkdirSync(basePath, { recursive: true });

            const csvWriter = createCsvWriter({
                // eslint-disable-next-line no-await-in-loop
                header: await generateSubContentCsv(
                    i,
                    j,
                    subAttributeCount,
                    subFactCount
                ),
                path: `${basePath}/${subDatasetName}.csv`
            });

            const records = generateRows(
                names,
                subAttributeCount,
                subFactCount,
                numberOfRows
            );

            csvWriter
                // eslint-disable-next-line no-await-in-loop
                .writeRecords(await records)
                .then(() => {
                    // eslint-disable-next-line no-console
                    console.log(`Generated ${subDatasetName}`);
                })
                .catch((err) => {
                    // eslint-disable-next-line no-console
                    console.error(`Failed to write ${subDatasetName}: ${err}`);
                });
        }
    }
}

module.exports = {
    generateCsvForMainDataset,
    generateCsvForSubDataset
};
