import * as lib from "ts-morph";
import fs from "fs";
import path from "path";
import { cleanType } from "./utils/index.js";

async function generateDto() {
  try {
    const project = new lib.Project();
    const configPath = "ngconfig.json";
    let rootFilePath;
    let destFilePath;
    let dtoDestFileName;
    let dtoSourceFolder;

    if (fs.existsSync(configPath)) {
      const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
      rootFilePath = config.rootFilePath;
      destFilePath = config.destFilePath;
      dtoDestFileName = config.dtoDestFileName || "dtos.d.ts";
      dtoSourceFolder = config.dtoSourceFolder || "dtos";
    } else {
      console.error("Config file not found: ngconfig.json");
      return;
    }

    if (!fs.existsSync(rootFilePath)) {
      console.error(`Dtos folder not found: ${rootFilePath}`);
      return;
    }

    const files = fs
      .readdirSync(`${rootFilePath}/${dtoSourceFolder}`)
      .filter((file) => file.endsWith(".dto.ts"));

    if (files.length === 0) {
      console.error(
        `No entity files found in folder: ${rootFilePath}/${dtoSourceFolder}`
      );
      return;
    }

    const destFile = project.createSourceFile(
      `${destFilePath}/${dtoDestFileName}`,
      "",
      {
        overwrite: true,
      }
    );
    console.log("Generating dtos for you, hold on... 🍕");
    files.forEach((file) => {
      const sourceFilePath = path.join(
        `${rootFilePath}/${dtoSourceFolder}`,
        file
      );
      const sourceFile = project.addSourceFileAtPath(sourceFilePath);
      const classDecls = sourceFile.getClasses();
      const interfaces = sourceFile.getInterfaces();
      const enums = sourceFile.getEnums();

      enums.forEach((enumDecl) => {
        destFile.addStatements((writer) => {
          writer.writeLine(`export enum I${enumDecl.getName()} {`);
          enumDecl.getMembers().forEach((member) => {
            writer.writeLine(`  ${member.getName()} = ${member.getValue()},`);
          });
          writer.writeLine(`}\n`);
        });
      });

      classDecls?.length > 0 &&
        classDecls?.forEach((classDecl) => {
          destFile.addStatements((writer) => {
            writer.writeLine(`export interface I${classDecl.getName()} {`);
            classDecl.getProperties().forEach((prop) => {
              const propName = prop.getName();
              const propType = cleanType(prop.getType().getText(sourceFile));
              writer.writeLine(`  ${propName}: ${propType};`);
            });
            writer.writeLine(`}\n`);
          });
        });

      interfaces.forEach((interfaceDecl) => {
        destFile.addStatements((writer) => {
          writer.writeLine(`export interface I${interfaceDecl.getName()}Dto {`);
          interfaceDecl.getProperties().forEach((prop) => {
            const propName = prop.getName();
            const propType = cleanType(prop.getType().getText(sourceFile));
            writer.writeLine(`  ${propName}: ${propType};`);
          });
          writer.writeLine(`}\n`);
        });
      });
    });
    console.log("DTOs generated successfully 🚀");
    await project.save();
  } catch (e) {
    console.log("error creating project", e);
  }
}

generateDto();
