import { execSync } from "child_process";
import * as fs from "fs";
import * as path from "path";
import * as dotenv from "dotenv";
import { fileURLToPath } from "url";
import * as readline from "readline";

// Get the directory name of the current module (ESM compatible)
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Function to ask user for deployment type
async function askDeploymentType() {
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  return new Promise((resolve) => {
    rl.question(
      "🚀 Choose deployment type:\n1. Production (prod)\n2. Staging (staging)\nEnter your choice (1 or 2): ",
      (answer) => {
        rl.close();
        const choice = answer.trim();
        if (choice === "1" || choice.toLowerCase() === "prod" || choice.toLowerCase() === "production") {
          resolve("production");
        } else if (choice === "2" || choice.toLowerCase() === "staging") {
          resolve("staging");
        } else {
          console.log("Invalid choice. Defaulting to staging deployment.");
          resolve("staging");
        }
      }
    );
  });
}

// Load environment variables from .env file
// This resolves to the root .env file from anywhere in the monorepo
const envPath = path.resolve(__dirname, ".env");

// Verify if the file exists
if (!fs.existsSync(envPath)) {
  console.error(`Error: Environment file not found at ${envPath}`);
  process.exit(1);
}

// Function to build Docker image
function buildDockerImage(imageName, npmToken) {
  try {
    console.log(`Building Docker image: ${imageName}`);

    // Remove existing image if it exists
    try {
      execSync(`docker image inspect ${imageName}`, { stdio: "ignore" });
      execSync(`docker rmi -f ${imageName}`, { stdio: "inherit" });
    } catch {
      console.log("No existing local image found. Continuing build...");
    }

    // Build the image using current directory as context
    const dockerfilePath = path.resolve(__dirname, "Dockerfile");
    const buildContext = __dirname;

    if (!npmToken) {
      console.error(
        "Error: NPM_TOKEN is not set in the environment variables."
      );
      console.error(
        "Please set NPM_TOKEN environment variable with your GitHub token."
      );
      console.error("Example: export NPM_TOKEN=ghp_your_github_token_here");
      process.exit(1);
    }

    console.log(`Using NPM_TOKEN: ${npmToken.substring(0, 4)}...`);

    // Build the image
    execSync(
      `docker build --no-cache --platform linux/amd64 -f "${dockerfilePath}" --build-arg NPM_TOKEN -t "${imageName}" "${buildContext}"`,
      {
        stdio: "inherit",
        env: { ...process.env, NPM_TOKEN: npmToken },
      }
    );

    console.log(`Docker image ${imageName} built successfully!`);
  } catch (error) {
    console.error("Error building Docker image:", error);
    throw error;
  }
}

async function deploy() {
  try {
    console.log("🚀 Starting DZap AI Deployment Process...");
    console.log("==========================================");

    // Ask user for deployment type
    const deploymentType = await askDeploymentType();
    console.log(`\n📋 Selected deployment type: ${deploymentType.toUpperCase()}`);
    console.log("----------------------------------------");

    const envConfig = dotenv.parse(fs.readFileSync(envPath));

    // Convert any \n string literals to actual newlines in environment variables
    // This is especially important for RSA keys
    Object.entries(envConfig).forEach(([key, value]) => {
      if (typeof value === "string" && value.includes("\\n")) {
        envConfig[key] = value.replace(/\\n/g, "\n");
        console.log(`Converted literal \\n to newlines in ${key}`);
      }
    });
    envConfig["NODE_ENV"] = deploymentType;
    delete envConfig["PORT"]; // Set PORT to undefined to use default Cloud Run port
    // Note: Cloud Run automatically assigns a port, so we don't need to set it explicitly

  // Build env vars string with proper YAML multiline handling
  const envYaml = Object.entries(envConfig)
    .map(([key, value]) => {
      // For multiline values (like RSA keys), use YAML block scalar
      if (typeof value === "string" && value.includes("\n")) {
        // Use the YAML literal style (|) which preserves all newlines
        return `${key}: |\n${value
          .split("\n")
          .map((line) => `  ${line}`)
          .join("\n")}`;
      }
      // For single line values with special characters, use quotes
      else if (typeof value === "string") {
        // Properly escape single quotes for YAML
        return `${key}: '${value.replace(/'/g, "''")}'`;
      }
      // For non-string values
      return `${key}: ${value}`;
    })
    .join("\n");

  fs.writeFileSync(path.resolve(__dirname, "env.yaml"), envYaml);

  console.log("\n📋 Environment Variables Loaded:");
  console.log("--------------------------------");
  // Log the first few characters of each env var for verification (safely)
  for (const [key, value] of Object.entries(envConfig)) {
    const safeValue =
      typeof value === "string"
        ? value.length > 4
          ? value.substring(0, 2) + "***"
          : "***"
        : "***";
    console.log(`${key}: ${safeValue}`);
  }

  // Build Docker image
  console.log("\n🐳 Building Docker Image...");
  console.log("---------------------------");
  
  // Configure project and service based on deployment type
  const project = deploymentType === "production" ? "dzapprod" : "dzapstaging";
  const service = "nlp-ai";
  const imageName =
    `europe-north1-docker.pkg.dev/${project}/docker-images/${service}:latest`;
  
  console.log(`📦 Project: ${project}`);
  console.log(`🔧 Service: ${service}`);
  console.log(`🐳 Image: ${imageName}`);
  
  buildDockerImage(imageName, envConfig["NPM_TOKEN"]);

  console.log("\n📤 Pushing image to Artifact Registry...");
  console.log("----------------------------------------");

  // Ensure Docker is authenticated with Google Cloud
  console.log("Configuring Docker for Artifact Registry...");
  execSync("gcloud auth configure-docker europe-north1-docker.pkg.dev", {
    stdio: "inherit",
  });

  execSync(`docker push ${imageName}`, { stdio: "inherit" });

  console.log("\n☁️  Deploying to Cloud Run...");
  console.log("-----------------------------");
  execSync(
    `gcloud config set project ${project} && \
    gcloud run deploy ${service} \
  --image ${imageName} \
  --platform managed \
  --region europe-north1 \
  --min-instances 0 \
  --memory 512Mi \
  --port=3001 \
  --env-vars-file=${path.resolve(__dirname, "env.yaml")} \
  --allow-unauthenticated`,
    { stdio: "inherit" }
  );

  fs.unlinkSync(path.resolve(__dirname, "env.yaml"));
  console.log(`\n✅ ${deploymentType.toUpperCase()} deployment completed successfully!`);
  console.log("=====================================");
  console.log(`🌐 Deployed to: ${project}`);
  console.log(`🔧 Service: ${service}`);
  console.log(`📦 Environment: ${deploymentType}`);
} catch (error) {
  console.error("Error processing environment variables:", error);
  process.exit(1);
} finally {
  // Clean up the env.yaml file if it exists
  const yamlPath = path.resolve(__dirname, "env.yaml");
  if (fs.existsSync(yamlPath)) {
    fs.unlinkSync(yamlPath);
    console.log("Cleaned up env.yaml file.");
  }
}
}

// Run the deployment
deploy().catch((error) => {
  console.error("Deployment failed:", error);
  process.exit(1);
});
