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

async function generateInterfaces(): Promise<void> {
  try {
    const project = new lib.Project();
    const configPath = "ngconfig.json";

    let rootFilePath;
    let destFilePath;
    let entityDestFileName;
    let entitySourceFolder;

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

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

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

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

    const destFile = project.createSourceFile(
      `${destFilePath}/${entityDestFileName}`,
      "",
      {
        overwrite: true,
      }
    );
    console.log("Generating models for you, hold on... 🍕");

    files.forEach((file) => {
      const sourceFilePath = path.join(
        `${rootFilePath}/${entitySourceFolder}`,
        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) => {
          if (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?.length > 0 &&
        interfaces.forEach((interfaceDecl) => {
          destFile.addStatements((writer) => {
            writer.writeLine(`export interface ${interfaceDecl.getName()} {`);
            interfaceDecl.getProperties().forEach((prop) => {
              const propName = prop.getName();
              const propType = cleanType(prop.getType().getText(sourceFile));
              writer.writeLine(`  ${propName}: ${propType};`);
            });
            writer.writeLine(`}\n`);
          });
        });
    });

    console.log("Models generated successfully 🚀");
    await project.save();
  } catch (e) {
    console.log("error creating project", e);
  }
}

generateInterfaces();
