import { LanguageSupport, type StreamParser } from "@codemirror/language";
import {linter as linterExtension, lintGutter } from "@codemirror/lint";
import type { Extension } from "@codemirror/state";
import { SupportedMimeTypes } from "@triliumnext/commons";

async function buildJavaScript(mimeType: string) {
    const { javascript, esLint } = await import('@codemirror/lang-javascript');
    const lint = (await import("./extensions/eslint.js")).lint;
    const extensions: Extension[] = [ javascript() ];

    const result = await lint(mimeType);
    if ("linter" in result) {
        const { linter, config } = result;
        extensions.push(linterExtension(esLint(linter, config)));
        extensions.push(lintGutter())
    }

    return extensions;
}

async function buildMermaid() {
    const { mermaid, foldByIndent } = (await import('codemirror-lang-mermaid'));
    return [ mermaid(), foldByIndent() ];
}

const byMimeType: Record<SupportedMimeTypes, (() => Promise<StreamParser<unknown> | LanguageSupport | Extension[]>) | null> = {
    "text/plain": null,

    "application/dart": async () => (await import('@codemirror/legacy-modes/mode/clike')).dart,
    "application/edn": async () => (await import('@codemirror/legacy-modes/mode/clojure')).clojure,
    "application/javascript;env=backend": async () => buildJavaScript("application/javascript;env=backend"),
    "application/javascript;env=frontend": async () => buildJavaScript("application/javascript;env=frontend"),
    "application/json": async () => ((await import('@codemirror/lang-json')).json()),
    "application/ld+json": async () => (await import('@codemirror/legacy-modes/mode/javascript')).jsonld,
    "application/mbox": async () => (await import('@codemirror/legacy-modes/mode/mbox')).mbox,
    "application/n-triples": async () => (await import('@codemirror/legacy-modes/mode/ntriples')).ntriples,
    "application/pgp": async () => (await import('@codemirror/legacy-modes/mode/asciiarmor')).asciiArmor,
    "application/sieve": async () => (await import('@codemirror/legacy-modes/mode/sieve')).sieve,
    "application/sparql-query": async () => (await import('@codemirror/legacy-modes/mode/sparql')).sparql,
    "application/typescript": async () => (await import('@codemirror/lang-javascript')).javascript({ typescript: true }),
    "application/vnd.kdl": null,
    "application/x-aspx": null,
    "application/x-bat": async () => (await import("./languages/batch.js")).batch,
    "application/x-cypher-query": async () => (await import('@codemirror/legacy-modes/mode/cypher')).cypher,
    "application/x-ejs": null,
    "application/x-erb": null,
    "application/x-jsp": null,
    "application/x-powershell": async () => (await import('@codemirror/legacy-modes/mode/powershell')).powerShell,
    "application/xml-dtd": async () => (await import('@codemirror/legacy-modes/mode/xml')).xml,
    "application/xquery": async () => (await import('@codemirror/legacy-modes/mode/xquery')).xQuery,
    "message/http": async () => (await import('@codemirror/legacy-modes/mode/http')).http,
    "text/apl": async () => (await import('@codemirror/legacy-modes/mode/apl')).apl,
    "text/coffeescript": async () => (await import('@codemirror/legacy-modes/mode/coffeescript')).coffeeScript,
    "text/css": async () => (await import('@codemirror/lang-css')).css(),
    "text/html": async () => (await import('@codemirror/lang-html')).html(),
    "text/jinja2": async () => (await import('@codemirror/legacy-modes/mode/jinja2')).jinja2,
    "text/jsx": async () => (await import('@codemirror/lang-javascript')).javascript({ jsx: true }),
    "text/mirc": async () => (await import('@codemirror/legacy-modes/mode/mirc')).mirc,
    "text/tiki": async () => (await import('@codemirror/legacy-modes/mode/tiki')).tiki,
    "text/troff": async () => (await import('@codemirror/legacy-modes/mode/troff')).troff,
    "text/turtle": async () => (await import('@codemirror/legacy-modes/mode/turtle')).turtle,
    "text/typescript-jsx": async () => (await import('@codemirror/lang-javascript')).javascript({ typescript: true, jsx: true }),
    "text/vbscript": async () => (await import('@codemirror/legacy-modes/mode/vbscript')).vbScript,
    "text/velocity": async () => (await import('@codemirror/legacy-modes/mode/velocity')).velocity,
    "text/vnd.mermaid": async () => buildMermaid(),
    "text/mermaid": async () => buildMermaid(),
    "text/x-asm-mips": null,
    "text/x-abap": async () => (await import('./languages/abap.js')).abapMode,
    "text/x-asterisk": async () => (await import('@codemirror/legacy-modes/mode/asterisk')).asterisk,
    "text/x-brainfuck": async () => (await import('@codemirror/legacy-modes/mode/brainfuck')).brainfuck,
    "text/x-c++src": async () => (await import('@codemirror/legacy-modes/mode/clike')).cpp,
    "text/x-cassandra": async () => (await import('@codemirror/legacy-modes/mode/sql')).cassandra,
    "text/x-clojure": async () => (await import('@codemirror/legacy-modes/mode/clojure')).clojure,
    "text/x-clojurescript": async () => (await import('@codemirror/legacy-modes/mode/clojure')).clojure,
    "text/x-cmake": async () => (await import('@codemirror/legacy-modes/mode/cmake')).cmake,
    "text/x-cobol": async () => (await import('@codemirror/legacy-modes/mode/cobol')).cobol,
    "text/x-common-lisp": async () => (await import('@codemirror/legacy-modes/mode/commonlisp')).commonLisp,
    "text/x-crystal": async () => (await import('@codemirror/legacy-modes/mode/crystal')).crystal,
    "text/x-csharp": async () => (await import('@codemirror/legacy-modes/mode/clike')).csharp,
    "text/x-csrc": async () => (await import('@codemirror/legacy-modes/mode/clike')).c,
    "text/x-cython": async () => (await import('@codemirror/legacy-modes/mode/python')).cython,
    "text/x-d": async () => (await import('@codemirror/legacy-modes/mode/d')).d,
    "text/x-diff": async () => (await import('@codemirror/legacy-modes/mode/diff')).diff,
    "text/x-django": null,
    "text/x-dockerfile": async () => (await import('@codemirror/legacy-modes/mode/dockerfile')).dockerFile,
    "text/x-dylan": async () => (await import('@codemirror/legacy-modes/mode/dylan')).dylan,
    "text/x-ebnf": async () => (await import('@codemirror/legacy-modes/mode/ebnf')).ebnf,
    "text/x-ecl": async () => (await import('@codemirror/legacy-modes/mode/ecl')).ecl,
    "text/x-eiffel": async () => (await import('@codemirror/legacy-modes/mode/eiffel')).eiffel,
    "text/x-elixir": async () => (await import('codemirror-lang-elixir')).elixir(),
    "text/x-elm": async () => (await import('@codemirror/legacy-modes/mode/elm')).elm,
    "text/x-erlang": async () => (await import('@codemirror/legacy-modes/mode/erlang')).erlang,
    "text/x-esper": async () => (await import('@codemirror/legacy-modes/mode/sql')).esper,
    "text/x-factor": async () => (await import('@codemirror/legacy-modes/mode/factor')).factor,
    "text/x-fcl": async () => (await import('@codemirror/legacy-modes/mode/fcl')).fcl,
    "text/x-feature": async () => (await import('@codemirror/legacy-modes/mode/gherkin')).gherkin,
    "text/x-forth": async () => (await import('@codemirror/legacy-modes/mode/forth')).forth,
    "text/x-fortran": async () => (await import('@codemirror/legacy-modes/mode/fortran')).fortran,
    "text/x-fsharp": async () => (await import('@codemirror/legacy-modes/mode/mllike')).fSharp,
    "text/x-gas": async () => (await import('@codemirror/legacy-modes/mode/gas')).gas,
    "text/x-gdscript": async () => (await import('./languages/gdscript.js')).gdscript,
    "text/x-gfm": async () => {
        const { markdown, markdownLanguage } = (await import('@codemirror/lang-markdown'));
        return markdown({
            base: markdownLanguage
        });
    },
    "text/x-go": async () => (await import('@codemirror/legacy-modes/mode/go')).go,
    "text/x-groovy": async () => (await import('@codemirror/legacy-modes/mode/groovy')).groovy,
    "text/x-gss": async () => (await import('@codemirror/legacy-modes/mode/css')).gss,
    "text/x-haml": null,
    "text/x-haskell": async () => (await import('@codemirror/legacy-modes/mode/haskell')).haskell,
    "text/x-haxe": async () => (await import('@codemirror/legacy-modes/mode/haxe')).haxe,
    "text/x-hcl": async () => (await import('codemirror-lang-hcl')).hcl(),
    "text/x-hxml": async () => (await import('@codemirror/legacy-modes/mode/haxe')).hxml,
    "text/x-idl": async () => (await import('@codemirror/legacy-modes/mode/idl')).idl,
    "text/x-java": async () => (await import('@codemirror/legacy-modes/mode/clike')).java,
    "text/x-julia": async () => (await import('@codemirror/legacy-modes/mode/julia')).julia,
    "text/x-pegjs": null,
    "text/x-kotlin": async () => (await import('@codemirror/legacy-modes/mode/clike')).kotlin,
    "text/x-latex": async () => (await import('@codemirror/legacy-modes/mode/stex')).stex,
    "text/x-less": async () => (await import('@codemirror/legacy-modes/mode/css')).less,
    "text/x-literate-haskell": null,
    "text/x-livescript": async () => (await import('@codemirror/legacy-modes/mode/livescript')).liveScript,
    "text/x-lua": async () => (await import('@codemirror/legacy-modes/mode/lua')).lua,
    "text/x-mariadb": async () => (await import('@codemirror/legacy-modes/mode/sql')).sqlite,
    "text/x-markdown": async () => ((await import('@codemirror/lang-markdown')).markdown()),
    "text/x-mathematica": async () => (await import('@codemirror/legacy-modes/mode/mathematica')).mathematica,
    "text/x-modelica": async () => (await import('@codemirror/legacy-modes/mode/modelica')).modelica,
    "text/x-mscgen": async () => (await import('@codemirror/legacy-modes/mode/mscgen')).mscgen,
    "text/x-msgenny": async () => (await import('@codemirror/legacy-modes/mode/mscgen')).msgenny,
    "text/x-mssql": async () => (await import('@codemirror/legacy-modes/mode/sql')).msSQL,
    "text/x-mumps": async () => (await import('@codemirror/legacy-modes/mode/mumps')).mumps,
    "text/x-mysql": async () => (await import('@codemirror/legacy-modes/mode/sql')).mySQL,
    "text/x-nix": async () => (await import('@replit/codemirror-lang-nix')).nix(),
    "text/x-nginx-conf": async () => (await import('@codemirror/legacy-modes/mode/nginx')).nginx,
    "text/x-nsis": async () => (await import('@codemirror/legacy-modes/mode/nsis')).nsis,
    "text/x-objectivec": async () => (await import('@codemirror/legacy-modes/mode/clike')).objectiveC,
    "text/x-ocaml": async () => (await import('@codemirror/legacy-modes/mode/mllike')).oCaml,
    "text/x-octave": async () => (await import('@codemirror/legacy-modes/mode/octave')).octave,
    "text/x-oz": async () => (await import('@codemirror/legacy-modes/mode/oz')).oz,
    "text/x-pascal": async () => (await import('@codemirror/legacy-modes/mode/pascal')).pascal,
    "text/x-perl": async () => (await import('@codemirror/legacy-modes/mode/perl')).perl,
    "text/x-pgsql": async () => (await import('@codemirror/legacy-modes/mode/sql')).pgSQL,
    "text/x-php": async () => ((await import('@codemirror/lang-php')).php()),
    "text/x-pig": async () => (await import('@codemirror/legacy-modes/mode/pig')).pig,
    "text/x-plsql": async () => (await import('@codemirror/legacy-modes/mode/sql')).plSQL,
    "text/x-properties": async () => (await import('@codemirror/legacy-modes/mode/properties')).properties,
    "text/x-protobuf": async () => (await import('@codemirror/legacy-modes/mode/protobuf')).protobuf,
    "text/x-pug": async () => (await import('@codemirror/legacy-modes/mode/pug')).pug,
    "text/x-puppet": async () => (await import('@codemirror/legacy-modes/mode/puppet')).puppet,
    "text/x-python": async () => (await import('@codemirror/legacy-modes/mode/python')).python,
    "text/x-q": async () => (await import('@codemirror/legacy-modes/mode/q')).q,
    "text/x-rpm-changes": async () => (await import('@codemirror/legacy-modes/mode/rpm')).rpmChanges,
    "text/x-rpm-spec": async () => (await import('@codemirror/legacy-modes/mode/rpm')).rpmSpec,
    "text/x-rsrc": async () => (await import('@codemirror/legacy-modes/mode/r')).r,
    "text/x-rst": null,
    "text/x-ruby": async () => (await import('@codemirror/legacy-modes/mode/ruby')).ruby,
    "text/x-rustsrc": async () => (await import('@codemirror/legacy-modes/mode/rust')).rust,
    "text/x-sas": async () => (await import('@codemirror/legacy-modes/mode/sas')).sas,
    "text/x-sass": async () => (await import('@codemirror/legacy-modes/mode/sass')).sass,
    "text/x-scala": async () => (await import('@codemirror/legacy-modes/mode/clike')).scala,
    "text/x-scheme": async () => (await import('@codemirror/legacy-modes/mode/scheme')).scheme,
    "text/x-scss": async () => (await import('@codemirror/legacy-modes/mode/css')).sCSS,
    "text/x-sh": async () => (await import('@codemirror/legacy-modes/mode/shell')).shell,
    "text/x-slim": null,
    "text/x-smarty": async () => ((await import('@ssddanbrown/codemirror-lang-smarty')).smarty),
    "text/x-sml": async () => (await import('@codemirror/legacy-modes/mode/mllike')).sml,
    "text/x-solr": async () => (await import('@codemirror/legacy-modes/mode/solr')).solr,
    "text/x-soy": null,
    "text/x-spreadsheet": async () => (await import('@codemirror/legacy-modes/mode/spreadsheet')).spreadsheet,
    "text/x-sql": async () => (await import('@codemirror/legacy-modes/mode/sql')).mySQL,
    "text/x-sqlite;schema=trilium": async () => (await import('@codemirror/legacy-modes/mode/sql')).sqlite,
    "text/x-sqlite": async () => (await import('@codemirror/legacy-modes/mode/sql')).sqlite,
    "text/x-squirrel": async () => (await import('@codemirror/legacy-modes/mode/clike')).squirrel,
    "text/x-stex": async () => (await import('@codemirror/legacy-modes/mode/stex')).stex,
    "text/x-stsrc": async () => (await import('@codemirror/legacy-modes/mode/smalltalk')).smalltalk,
    "text/x-styl": async () => (await import('@codemirror/legacy-modes/mode/stylus')).stylus,
    "text/x-swift": async () => (await import('@codemirror/legacy-modes/mode/swift')).swift,
    "text/x-systemverilog": async () => (await import('@codemirror/legacy-modes/mode/verilog')).verilog,
    "text/x-tcl": async () => (await import('@codemirror/legacy-modes/mode/tcl')).tcl,
    "text/x-textile": async () => (await import('@codemirror/legacy-modes/mode/textile')).textile,
    "text/x-tiddlywiki": async () => (await import('@codemirror/legacy-modes/mode/tiddlywiki')).tiddlyWiki,
    "text/x-toml": async () => (await import('@codemirror/legacy-modes/mode/toml')).toml,
    "text/x-tornado": null,
    "text/x-ttcn-asn": async () => (await import('@codemirror/legacy-modes/mode/ttcn')).ttcn,
    "text/x-ttcn-cfg": async () => (await import('@codemirror/legacy-modes/mode/ttcn-cfg')).ttcnCfg,
    "text/x-ttcn": async () => (await import('@codemirror/legacy-modes/mode/ttcn')).ttcn,
    "text/x-twig": async () => ((await import('@ssddanbrown/codemirror-lang-twig')).twig()),
    "text/x-vb": async () => (await import('@codemirror/legacy-modes/mode/vb')).vb,
    "text/x-verilog": async () => (await import('@codemirror/legacy-modes/mode/verilog')).verilog,
    "text/x-vhdl": async () => (await import('@codemirror/legacy-modes/mode/vhdl')).vhdl,
    "text/x-vue": async () => ((await import('@codemirror/lang-vue')).vue()),
    "text/x-webidl": async () => (await import('@codemirror/legacy-modes/mode/webidl')).webIDL,
    "text/x-xu": async () => (await import('@codemirror/legacy-modes/mode/mscgen')).xu,
    "text/x-yacas": async () => (await import('@codemirror/legacy-modes/mode/yacas')).yacas,
    "text/x-yaml": async () => (await import('@codemirror/legacy-modes/mode/yaml')).yaml,
    "text/x-z80": async () => (await import('@codemirror/legacy-modes/mode/z80')).z80,
    "text/xml": async () => (await import('@codemirror/lang-xml')).xml()
}

export default byMimeType;
