import * as fs from "fs";
import * as path from "path";
import { crawl } from "./crawl";
import { id } from "tsafe/id";

type TransformSourceCode = (params: { sourceCode: Buffer; filePath: string }) =>
    | {
          modifiedSourceCode: Buffer;
          newFileName?: string;
      }
    | undefined;

/** Apply a transformation function to every file of directory */
export function transformCodebase(params: { srcDirPath: string; destDirPath: string; transformSourceCode?: TransformSourceCode }) {
    const {
        srcDirPath,
        destDirPath,
        transformSourceCode = id<TransformSourceCode>(({ sourceCode }) => ({
            "modifiedSourceCode": sourceCode,
        })),
    } = params;

    for (const file_relative_path of crawl(srcDirPath)) {
        const filePath = path.join(srcDirPath, file_relative_path);

        const transformSourceCodeResult = transformSourceCode({
            "sourceCode": fs.readFileSync(filePath),
            "filePath": path.join(srcDirPath, file_relative_path),
        });

        if (transformSourceCodeResult === undefined) {
            continue;
        }

        fs.mkdirSync(path.dirname(path.join(destDirPath, file_relative_path)), {
            "recursive": true,
        });

        const { newFileName, modifiedSourceCode } = transformSourceCodeResult;

        fs.writeFileSync(
            path.join(path.dirname(path.join(destDirPath, file_relative_path)), newFileName ?? path.basename(file_relative_path)),
            modifiedSourceCode,
        );
    }
}
