import CodeMirror from "@uiw/react-codemirror";
import { sql, PostgreSQL, StandardSQL } from "@codemirror/lang-sql";
import { keymap } from "@codemirror/view";
import { useCallback, useMemo } from "react";
import { useAppStore } from "@/stores/app-store";
import { tuskEditorExtensions } from "@/lib/editor-theme";

interface Props {
  value: string;
  onChange: (value: string) => void;
  onExecute: () => void;
  onFormat?: () => void;
  schema?: Record<string, Record<string, string[]>>;
}

function buildSqlNamespace(
  schema: Record<string, Record<string, string[]>>
): Record<string, string[]> {
  const ns: Record<string, string[]> = {};
  for (const [schemaName, tables] of Object.entries(schema)) {
    for (const [tableName, columns] of Object.entries(tables)) {
      ns[`${schemaName}.${tableName}`] = columns;
      if (schemaName === "public") {
        ns[tableName] = columns;
      }
    }
  }
  return ns;
}

export function SqlEditor({ value, onChange, onExecute, onFormat, schema }: Props) {
  const activeConnectionId = useAppStore((s) => s.activeConnectionId);
  const dbFlavors = useAppStore((s) => s.dbFlavors);
  const flavor = activeConnectionId ? dbFlavors[activeConnectionId] : undefined;

  const handleChange = useCallback(
    (val: string) => {
      onChange(val);
    },
    [onChange]
  );

  const extensions = useMemo(() => {
    const sqlNamespace = schema ? buildSqlNamespace(schema) : undefined;
    const dialect = flavor === "clickhouse" ? StandardSQL : PostgreSQL;
    const defaultSchema = flavor === "clickhouse" ? undefined : "public";
    return [
      tuskEditorExtensions,
      sql({
        dialect,
        schema: sqlNamespace,
        defaultSchema,
      }),
      keymap.of([
        {
          key: "Ctrl-Enter",
          run: () => {
            onExecute();
            return true;
          },
        },
        {
          key: "Mod-Enter",
          run: () => {
            onExecute();
            return true;
          },
        },
        {
          key: "Shift-Alt-f",
          run: () => {
            onFormat?.();
            return true;
          },
        },
      ]),
    ];
  }, [onExecute, onFormat, schema, flavor]);

  return (
    <CodeMirror
      value={value}
      onChange={handleChange}
      extensions={extensions}
      // height="100%" propagates down to .cm-editor so the inner .cm-scroller
      // can render a vertical scrollbar; without it, long queries overflow the
      // flex container and the editor cannot be scrolled.
      height="100%"
      className="h-full text-sm [&_.cm-editor]:h-full"
      basicSetup={{
        lineNumbers: true,
        foldGutter: true,
        highlightActiveLine: true,
        autocompletion: true,
      }}
    />
  );
}
