import { execSync } from "node:child_process"
import fs from "node:fs/promises"
import path from "node:path"

// Strip JSONC comments while preserving strings (regex matches strings first to skip them)
const stripJsoncComments = (jsonc: string): string =>
  jsonc.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\/\/[^\n]*|\/\*[\s\S]*?\*\//g, (match) =>
    match.startsWith("/") ? "" : match,
  )

const extensionsJson = {
  recommendations: ["oxc.oxc-vscode"],
  unwantedRecommendations: [
    "ms-vscode.vscode-typescript-next",
    "ms-vscode.vscode-typescript-tslint-plugin",
    "eg2.tslint",
    "zuoez02.tslint-snippets",
    "dbaeumer.jshint",
    "hookyqr.beautify",
    "felipecaputo.git-project-manager",
    "donjayamanne.githistory",
    "ms-azuretools.vscode-docker",
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
  ],
}

const settingsJson = {
  // General optimizations
  "extensions.ignoreRecommendations": false,
  "editor.tabSize": 2,
  "editor.formatOnSave": true,
  "editor.linkedEditing": true,
  "editor.suggest.snippetsPreventQuickSuggestions": false,
  "editor.defaultFormatter": "oxc.oxc-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll": "explicit",
    "source.organizeImports": "never",
  },
  "files.insertFinalNewline": true,
  "files.associations": {
    "tsconfig.json": "jsonc",
  },
  "files.watcherExclude": {
    "**/.git/objects/**": true,
    "**/.git/subtree-cache/**": true,
    "**/node_modules/**": true,
    "**/dist/**": true,
    "**/tmp/**": true,
    "**/public/**": true,
  },
  "task.autoDetect": "off",
  "npm.autoDetect": "off",
  "search.useIgnoreFiles": false,
  "search.exclude": {
    "**/node_modules": true,
    "**/dist": true,
  },
  // VSCode CodeLens
  "javascript.referencesCodeLens.enabled": true,
  "typescript.implementationsCodeLens.enabled": true,
  "typescript.referencesCodeLens.enabled": true,

  "typescript.tsdk": "node_modules/typescript",
  "typescript.tsserver.maxTsServerMemory": 8192,
  "typescript.disableAutomaticTypeAcquisition": true,
  "typescript.check.npmIsInstalled": false,
  "typescript.tsserver.log": "off",
  "typescript.autoClosingTags": true,
  "typescript.format.enable": false,
  "typescript.tsserver.useSyntaxServer": "auto",
  "typescript.validate.enable": true,
  "typescript.preferences.importModuleSpecifier": "non-relative",
  "typescript.preferences.importModuleSpecifierEnding": "minimal",
  // Todo
  "todo-tree.ripgrep.ripgrepArgs": "--max-columns=1000 --no-config -i",
  "todo-tree.regex.regex": "((\\*|//|#|<!--|;|/\\*|^)\\s*($TAGS)|^\\s*- \\[ \\])",
  "todo-tree.general.tags": ["@todo", "TODO"],
}

const sortObjectKeys = <T extends Record<string, unknown>>(obj: T): T => {
  const sorted = {} as T
  for (const key of Object.keys(obj).sort()) {
    sorted[key as keyof T] = obj[key as keyof T]
  }
  return sorted
}

export const setupVSCode = async (cwd: string) => {
  const vscodeDir = path.join(cwd, ".vscode")

  await fs.mkdir(vscodeDir, { recursive: true })

  const extensionsPath = path.join(vscodeDir, "extensions.json")
  const sortedExtensions = {
    recommendations: extensionsJson.recommendations.sort(),
    unwantedRecommendations: extensionsJson.unwantedRecommendations.sort(),
  }
  await fs.writeFile(extensionsPath, JSON.stringify(sortedExtensions, null, 2) + "\n")
  console.info(`Written: ${extensionsPath}`)

  const settingsPath = path.join(vscodeDir, "settings.json")

  // Preserve certain settings from existing file
  let existingSettings: Record<string, unknown> = {}
  try {
    const existingContent = await fs.readFile(settingsPath, "utf8")
    existingSettings = JSON.parse(stripJsoncComments(existingContent))
  } catch (error) {
    console.error("Error reading or parsing settings.json:", error)
    // File doesn't exist or is invalid JSON, start fresh
  }

  const sortedSettings: Record<string, unknown> = sortObjectKeys(settingsJson)

  if (existingSettings["serverlessConsole.services"]) {
    sortedSettings["serverlessConsole.services"] = existingSettings["serverlessConsole.services"] // Add serverlessConsole.services last (after sorting) to keep it at the bottom
  }

  await fs.writeFile(settingsPath, JSON.stringify(sortedSettings, null, 2) + "\n")
  console.info(`Written: ${settingsPath}`)
  execSync("bunx oxfmt", { cwd: vscodeDir, stdio: `inherit` })
}
