#!/usr/bin/env node

/**
 * Git post-checkout hook for auto-configuring worktree environments.
 * This runs after 'git checkout' or 'git worktree add'.
 *
 * Args from git:
 *   process.argv[2] - previous HEAD ref
 *   process.argv[3] - new HEAD ref
 *   process.argv[4] - flag (1 = branch checkout, 0 = file checkout)
 */

import fs from "fs";
import path from "path";
import { execSync, execFileSync } from "child_process";
import { fileURLToPath } from "url";

const __dirname = path.dirname(fileURLToPath(import.meta.url));

const isBranchCheckout = process.argv[4] === "1";

if (!isBranchCheckout) {
  process.exit(0);
}

// Check if we're in a worktree by looking for .git file (not directory)
const gitPath = path.join(process.cwd(), ".git");
const isWorktree = fs.existsSync(gitPath) && fs.statSync(gitPath).isFile();

if (!isWorktree) {
  process.exit(0);
}

const envLocalPath = path.join(process.cwd(), ".env.local");

// Don't overwrite existing .env.local
if (fs.existsSync(envLocalPath)) {
  process.exit(0);
}

console.log("Detected new worktree - configuring ports in .env.local");

const CLIENT_PORT_BASE = 1420;
const PROXY_PORT_BASE = 2420; // Keep proxy +1000 from client to avoid cross-app conflicts

// Find the highest worktree index and MCP port in use across all worktrees.
// Main worktree (first in list) is assumed to use index 0:
// client=1420, proxy=2420, mcp=64343.
let maxMcpPort = 64343;
let maxWorktreeIndex = 0;

try {
  const worktreeList = execSync("git worktree list --porcelain", {
    encoding: "utf8",
  });
  const worktreePaths = worktreeList
    .split("\n")
    .filter((line) => line.startsWith("worktree "))
    .map((line) => line.replace("worktree ", "").trim());

  // Skip the first worktree (main) since it uses default ports
  for (let i = 1; i < worktreePaths.length; i++) {
    const worktreePath = worktreePaths[i];
    const envPath = path.join(worktreePath, ".env.local");

    if (fs.existsSync(envPath)) {
      const content = fs.readFileSync(envPath, "utf8");

      const mcpMatch = content.match(/^YAAK_PLUGIN_MCP_SERVER_PORT=(\d+)/m);
      if (mcpMatch) {
        const port = parseInt(mcpMatch[1], 10);
        if (port > maxMcpPort) {
          maxMcpPort = port;
        }
      }

      const clientDevMatch = content.match(
        /^(?:YAAK_CLIENT_DEV_PORT|YAAK_DEV_PORT)=(\d+)/m,
      );
      if (clientDevMatch) {
        const port = parseInt(clientDevMatch[1], 10);
        const index = port - CLIENT_PORT_BASE;
        if (index > maxWorktreeIndex) {
          maxWorktreeIndex = index;
        }
      }

      const proxyDevMatch = content.match(/^YAAK_PROXY_DEV_PORT=(\d+)/m);
      if (proxyDevMatch) {
        const port = parseInt(proxyDevMatch[1], 10);
        const index = port - PROXY_PORT_BASE;
        if (index > maxWorktreeIndex) {
          maxWorktreeIndex = index;
        }
      }
    }
  }

  // Increment MCP to get the next available port
  maxMcpPort++;
} catch (err) {
  console.error(
    "Warning: Could not check other worktrees for port conflicts:",
    err.message,
  );
  // Continue with default ports
}

const nextWorktreeIndex = maxWorktreeIndex + 1;
const nextClientDevPort = CLIENT_PORT_BASE + nextWorktreeIndex;
const nextProxyDevPort = PROXY_PORT_BASE + nextWorktreeIndex;

// Get worktree name from current directory
const worktreeName = path.basename(process.cwd());

// Create .env.local with unique ports
const envContent = `# Auto-generated by git post-checkout hook
# This file configures ports for this worktree to avoid conflicts

# Vite dev server port for the client app (main worktree uses ${CLIENT_PORT_BASE})
YAAK_CLIENT_DEV_PORT=${nextClientDevPort}

# Vite dev server port for the proxy app (main worktree uses ${PROXY_PORT_BASE})
YAAK_PROXY_DEV_PORT=${nextProxyDevPort}

# MCP Server port (main worktree uses 64343)
YAAK_PLUGIN_MCP_SERVER_PORT=${maxMcpPort}
`;

fs.writeFileSync(envLocalPath, envContent, "utf8");
console.log(
  `Created .env.local with YAAK_CLIENT_DEV_PORT=${nextClientDevPort}, YAAK_PROXY_DEV_PORT=${nextProxyDevPort}, and YAAK_PLUGIN_MCP_SERVER_PORT=${maxMcpPort}`,
);

// Create tauri.worktree.conf.json with unique app identifier for complete isolation
// This gives each worktree its own app data directory, avoiding the need for DB path prefixes
const clientTauriWorktreeConfig = {
  identifier: `app.yaak.desktop.dev.${worktreeName}`,
  productName: `Daak (${worktreeName})`,
};

const clientTauriConfigPath = path.join(
  process.cwd(),
  "crates-tauri",
  "yaak-app-client",
  "tauri.worktree.conf.json",
);
fs.writeFileSync(
  clientTauriConfigPath,
  JSON.stringify(clientTauriWorktreeConfig, null, 2) + "\n",
  "utf8",
);
console.log(
  `Created client tauri.worktree.conf.json with identifier: ${clientTauriWorktreeConfig.identifier}`,
);

const proxyTauriWorktreeConfig = {
  identifier: `app.yaak.proxy.dev.${worktreeName}`,
  productName: `Yaak Proxy (${worktreeName})`,
};

const proxyTauriConfigPath = path.join(
  process.cwd(),
  "crates-tauri",
  "yaak-app-proxy",
  "tauri.worktree.conf.json",
);
fs.writeFileSync(
  proxyTauriConfigPath,
  JSON.stringify(proxyTauriWorktreeConfig, null, 2) + "\n",
  "utf8",
);
console.log(
  `Created proxy tauri.worktree.conf.json with identifier: ${proxyTauriWorktreeConfig.identifier}`,
);

// Copy gitignored editor config folders from main worktree (.zed, .vscode, .claude, etc.)
// This ensures your editor settings, tasks, and configurations are available in the new worktree
// without needing to manually copy them or commit them to git.
try {
  const worktreeList = execSync("git worktree list --porcelain", {
    encoding: "utf8",
  });
  const mainWorktreePath = worktreeList
    .split("\n")
    .find((line) => line.startsWith("worktree "))
    ?.replace("worktree ", "")
    .trim();

  if (mainWorktreePath) {
    // Find all .* folders in main worktree root that are gitignored
    const entries = fs.readdirSync(mainWorktreePath, { withFileTypes: true });
    const dotFolders = entries
      .filter((entry) => entry.isDirectory() && entry.name.startsWith("."))
      .map((entry) => entry.name);

    for (const folder of dotFolders) {
      const sourcePath = path.join(mainWorktreePath, folder);
      const destPath = path.join(process.cwd(), folder);

      try {
        // Check if it's gitignored - run from main worktree directory
        execFileSync("git", ["check-ignore", "-q", folder], {
          stdio: "pipe",
          cwd: mainWorktreePath,
        });

        // It's gitignored, copy it
        fs.cpSync(sourcePath, destPath, { recursive: true });
        console.log(`Copied ${folder} from main worktree`);
      } catch {
        // Not gitignored or doesn't exist, skip
      }
    }
  }
} catch (err) {
  console.warn(
    "Warning: Could not copy files from main worktree:",
    err.message,
  );
  // Continue anyway
}

console.log(
  "\n✓ Worktree setup complete! Run `npm run init` to install dependencies.",
);
