#!/usr/bin/env node

import { Command } from "commander";
import * as chalk from "chalk";
import * as path from "path";
import * as fs from "fs";
import * as inquirer from "inquirer";
import * as ora from "ora";
import { execSync } from "child_process";

const program = new Command();

const packageJson = JSON.parse(
  fs.readFileSync(path.join(__dirname, "../../package.json"), "utf8"),
);

program
  .name("texagon-nestjs-health")
  .description(
    "A CLI to add comprehensive health monitoring to NestJS applications",
  )
  .version(packageJson.version);

program
  .command("install")
  .description("Install health monitoring module into your NestJS application")
  .option("--no-deps", "Skip installing dependencies")
  .option("--path <path>", "Path to the NestJS application", process.cwd())
  .option("--prefix <prefix>", "Route prefix for health endpoints", "health")
  .action(async (options) => {
    console.log(chalk.blue("🚀 Installing NestJS Health Monitor..."));

    const targetPath = path.resolve(options.path);
    console.log(chalk.gray(`Target path: ${targetPath}`));

    if (!fs.existsSync(path.join(targetPath, "nest-cli.json"))) {
      console.error(
        chalk.red(
          "❌ This does not appear to be a NestJS project. Please run this command in a NestJS project.",
        ),
      );
      process.exit(1);
    }

    const answers = await inquirer.prompt([
      {
        type: "confirm",
        name: "enableMemoryMonitoring",
        message: "Enable memory monitoring?",
        default: true,
      },
      {
        type: "confirm",
        name: "enableDiskMonitoring",
        message: "Enable disk monitoring?",
        default: true,
      },
      {
        type: "input",
        name: "diskPath",
        message: "Path to monitor for disk space:",
        default: "/",
        when: (answers) => answers.enableDiskMonitoring,
      },
      {
        type: "number",
        name: "diskThresholdPercent",
        message: "Disk usage threshold percentage (0-100):",
        default: 75,
        when: (answers) => answers.enableDiskMonitoring,
        validate: (input) => {
          const num = parseFloat(input);
          return num >= 0 && num <= 100
            ? true
            : "Please enter a number between 0 and 100";
        },
      },
      {
        type: "confirm",
        name: "passwordProtected",
        message: "Enable password protection for health endpoints?",
        default: false,
      },
      {
        type: "password",
        name: "password",
        message: "Enter password for health endpoints:",
        when: (answers) => answers.passwordProtected,
        validate: (input) => {
          return input.length >= 6
            ? true
            : "Password must be at least 6 characters long";
        },
      },
      {
        type: "password",
        name: "confirmPassword",
        message: "Confirm password:",
        when: (answers) => answers.passwordProtected,
        validate: (input, answers) => {
          return input === answers.password ? true : "Passwords do not match";
        },
      },
    ]);

    if (answers.diskThresholdPercent) {
      answers.diskThresholdPercent = answers.diskThresholdPercent / 100;
    }

    const sourceDir = path.join(__dirname, "../health");
    const targetDir = path.join(targetPath, "src/health");

    const spinner = ora("Creating health module...").start();

    try {
      if (!fs.existsSync(targetDir)) {
        fs.mkdirSync(targetDir, { recursive: true });
      }

      const files = fs.readdirSync(sourceDir);
      files.forEach((file) => {
        if (file === "test-error.controller.ts") {
          return;
        }

        const source = path.join(sourceDir, file);
        const target = path.join(targetDir, file);

        fs.copyFileSync(source, target);
      });

      const appModulePath = path.join(targetPath, "src/app.module.ts");
      if (fs.existsSync(appModulePath)) {
        let appModuleContent = fs.readFileSync(appModulePath, "utf8");

        if (!appModuleContent.includes("HealthModule")) {
          appModuleContent = appModuleContent.replace(
            /(import.*from.*;\n)/,
            `$1import { HealthModule } from './health/health.module';\n`,
          );

          appModuleContent = appModuleContent.replace(
            /(imports\s*:\s*\[)/,
            `$1\n    HealthModule.register({\n      enableMemoryMonitoring: ${answers.enableMemoryMonitoring},\n      enableDiskMonitoring: ${answers.enableDiskMonitoring},\n      ${answers.diskPath ? `diskPath: '${answers.diskPath}',\n      ` : ""}${answers.diskThresholdPercent ? `diskThresholdPercent: ${answers.diskThresholdPercent},\n      ` : ""}${answers.passwordProtected ? `passwordProtected: true,\n      password: '${answers.password}',\n      ` : ""}routePrefix: '${options.prefix}',\n    }),`,
          );

          fs.writeFileSync(appModulePath, appModuleContent);
        }
      }

      spinner.succeed("Health module created successfully");

      if (options.deps) {
        spinner.text = "Installing dependencies...";
        spinner.start();

        try {
          execSync("npm install @nestjs/terminus @nestjs/axios", {
            cwd: targetPath,
            stdio: "ignore",
          });
          spinner.succeed("Dependencies installed successfully");
        } catch (error) {
          spinner.fail("Failed to install dependencies");
          console.error(chalk.red(`Error: ${error.message}`));
        }
      }

      console.log(
        "\n" + chalk.green("==>[SUCCESS] NestJS Health Monitor installed successfully!"),
      );
      console.log("\n" + chalk.yellow("Available endpoints:"));
      console.log(chalk.cyan(`- GET /${options.prefix}`));
      console.log(chalk.cyan(`- GET /${options.prefix}/live`));
      console.log(chalk.cyan(`- GET /${options.prefix}/ready`));
      console.log(chalk.cyan(`- GET /${options.prefix}/stats`));
    } catch (error) {
      spinner.fail("Failed to create health module");
      console.error(chalk.red(`Error: ${error.message}`));
    }
  });

program.parse();
