import type { Extension } from "@codemirror/state";
import { StreamLanguage } from "@codemirror/language";

const languageLoaders: Record<string, () => Promise<Extension>> = {
  javascript: async () => {
    const { javascript } = await import("@codemirror/lang-javascript");
    return javascript({ jsx: true });
  },
  typescript: async () => {
    const { javascript } = await import("@codemirror/lang-javascript");
    return javascript({ jsx: true, typescript: true });
  },
  python: async () => {
    const { python } = await import("@codemirror/lang-python");
    return python();
  },
  rust: async () => {
    const { rust } = await import("@codemirror/lang-rust");
    return rust();
  },
  cpp: async () => {
    const { cpp } = await import("@codemirror/lang-cpp");
    return cpp();
  },
  java: async () => {
    const { java } = await import("@codemirror/lang-java");
    return java();
  },
  go: async () => {
    const { go } = await import("@codemirror/lang-go");
    return go();
  },
  php: async () => {
    const { php } = await import("@codemirror/lang-php");
    return php();
  },
  sql: async () => {
    const { sql } = await import("@codemirror/lang-sql");
    return sql();
  },
  html: async () => {
    const { html } = await import("@codemirror/lang-html");
    return html();
  },
  css: async () => {
    const { css } = await import("@codemirror/lang-css");
    return css();
  },
  json: async () => {
    const { json } = await import("@codemirror/lang-json");
    return json();
  },
  xml: async () => {
    const { xml } = await import("@codemirror/lang-xml");
    return xml();
  },
  markdown: async () => {
    const { markdown } = await import("@codemirror/lang-markdown");
    return markdown();
  },
  yaml: async () => {
    const { yaml } = await import("@codemirror/lang-yaml");
    return yaml();
  },
  shell: async () => {
    const { shell } = await import("@codemirror/legacy-modes/mode/shell");
    return StreamLanguage.define(shell);
  },
  toml: async () => {
    const { toml } = await import("@codemirror/legacy-modes/mode/toml");
    return StreamLanguage.define(toml);
  },
  dockerfile: async () => {
    const { dockerFile } = await import("@codemirror/legacy-modes/mode/dockerfile");
    return StreamLanguage.define(dockerFile);
  },
};

const extToLanguage: Record<string, string> = {
  js: "javascript",
  mjs: "javascript",
  cjs: "javascript",
  jsx: "javascript",
  ts: "typescript",
  tsx: "typescript",
  mts: "typescript",
  cts: "typescript",
  py: "python",
  pyw: "python",
  rs: "rust",
  c: "cpp",
  h: "cpp",
  cpp: "cpp",
  cxx: "cpp",
  cc: "cpp",
  hpp: "cpp",
  hxx: "cpp",
  java: "java",
  go: "go",
  php: "php",
  sql: "sql",
  html: "html",
  htm: "html",
  svelte: "html",
  vue: "html",
  css: "css",
  scss: "css",
  less: "css",
  json: "json",
  jsonc: "json",
  xml: "xml",
  svg: "xml",
  md: "markdown",
  mdx: "markdown",
  markdown: "markdown",
  yaml: "yaml",
  yml: "yaml",
  sh: "shell",
  bash: "shell",
  zsh: "shell",
  fish: "shell",
  toml: "toml",
  dockerfile: "dockerfile",
};

const filenameToLanguage: Record<string, string> = {
  Dockerfile: "dockerfile",
  Makefile: "shell",
  Jenkinsfile: "java",
};

export function detectLanguage(filename: string): string {
  if (filenameToLanguage[filename]) {
    return filenameToLanguage[filename];
  }
  const ext = filename.split(".").pop()?.toLowerCase() ?? "";
  return extToLanguage[ext] ?? "plaintext";
}

export async function getLanguageExtension(language: string): Promise<Extension | null> {
  const loader = languageLoaders[language];
  if (!loader) return null;
  return loader();
}

export function getLanguageDisplayName(language: string): string {
  const names: Record<string, string> = {
    javascript: "JavaScript",
    typescript: "TypeScript",
    python: "Python",
    rust: "Rust",
    cpp: "C/C++",
    java: "Java",
    go: "Go",
    php: "PHP",
    sql: "SQL",
    html: "HTML",
    css: "CSS",
    json: "JSON",
    xml: "XML",
    markdown: "Markdown",
    yaml: "YAML",
    shell: "Shell",
    toml: "TOML",
    dockerfile: "Dockerfile",
    plaintext: "Plain Text",
  };
  return names[language] ?? language;
}

export const supportedLanguages = Object.keys(languageLoaders).concat("plaintext");
