import replace from 'replace-in-file';
import logger from "../libs/logger";
import { constants } from "node:fs/promises";
import Path from "path";
import { rootPath } from 'get-root-path';
import { mkdir } from 'node:fs/promises';
import { access } from 'node:fs';
import { copy } from 'fs-extra';
import { glob } from 'glob';

const setupScaffoldFiles = async (routeName: string, method: string, template: string) => {
    const methodType = method.toLocaleLowerCase();
    try {
        const targetDir = Path.join(rootPath, 'routes', routeName);

        await mkdir(targetDir).then(() => {
            access(targetDir, constants.W_OK, async (err) => {
                logger.info(err);
                if (err) {
                    throw Error('Copy failed');
                } else {
                    await copyScaffoldFiles(routeName, method, template)
                    await replacePlaceHolders(/TYPE/g, methodType, `${rootPath}/routes/${routeName}/*.ts`)
                    await replacePlaceHolders(/PATH/g, routeName, `${rootPath}/routes/${routeName}/*.ts`);
                }

            })
        });

        return true;
    } catch (e) {
        logger.info(e);
        return false;
    }
}

const replacePlaceHolders = async (placeholder: RegExp, replacement: string, filePath: string) => {

    const formattedPath = formatPath(filePath);

    const opts = {
        files: formattedPath,
        // Takes REGEX, /\$PATH\$/g for routename placeholders, /\$TYPE\$/g for method
        from: placeholder,
        to: replacement,
    };

    const fileDir = filePath.replace('/*.ts', '');

    access(fileDir, constants.W_OK, async (err) => {
        const files = await glob(formattedPath);

        if (err || !files.some) {
            logger.info(err)
            throw Error('Replace failed, files not found.')
        }

        access(files[0], constants.W_OK, async (fileErr) => {
            if (fileErr) {
                throw Error('Cannot read file');
            }

            const replaceResult = replace.sync(opts);
            logger.info(replaceResult);
            return;
        });

    });

    return;
}

const copyScaffoldFiles = async (routeName: string, pageType: string, templateType: string): Promise<void> => {

    const templateFilename = `${routeName}.njk`;
    const templateName = `${templateType}.njk`
    const routeDest = `/routes/${routeName}`

    logger.info(`Creating page: ${routeName} with template ${templateType}`);

    const templatePath = Path.join(rootPath, '/scaffold/pages', templateName);
    let routePath = Path.join(rootPath, '/scaffold/templates/other');

    if (pageType == 'page') {
        routePath = Path.join(rootPath, '/scaffold/templates/page');
    }

    try {
        await copy(templatePath, Path.join(rootPath, 'views', templateFilename));
        logger.info(`Page created: ${Path.join(rootPath, routeDest, templateFilename)}`);
    } catch (copyErr) {
        if (copyErr) {
            logger.debug(copyErr);
        }
    }

    try {
        const filterFiles = (source: string) => {
            if (pageType === 'get' && source.includes('post')) {
                return false;
            }

            if (pageType === 'post' && source.includes('get')) {
                return false;
            }
            return true;
        }
        await copy(routePath, Path.join(rootPath, routeDest), { filter: filterFiles })
        logger.info(`Files created: ${Path.join(rootPath, routeDest)}`);
    } catch (err) {
        throw Error('Copy templates failed');
    }

    const globPath = formatPath(Path.join(rootPath, routeDest));
    const createdFiles = await glob(globPath + '/*.ts');

    if (!createdFiles.some) {
        throw Error('Cannot read templates');
    }

    return;
}

const formatPath = (path: string) => {
    const { platform } = process;
    const locale = Path[platform === `win32` ? `win32` : `posix`];

    return path.split(Path.sep).join(locale.sep);
}

export { setupScaffoldFiles, copyScaffoldFiles, replacePlaceHolders }