<template>
  <field v-bind="$props">
    <div class="code-mirror">
      <Codemirror
        v-model="input"
        :disabled="disabled"
        :autofocus="true"
        :indent-with-tab="true"
        :tab-size="4"
        :extensions="extensions"
      />
    </div>
  </field>
</template>

<script setup lang="ts">
import { FieldComponentProps } from '@/plugins/field/field-component.model';
import { css } from '@codemirror/lang-css';
import { html } from '@codemirror/lang-html';
import { javascript } from '@codemirror/lang-javascript';
import { json, jsonParseLinter } from '@codemirror/lang-json';
import { linter, lintGutter } from '@codemirror/lint';
import { EditorView } from '@codemirror/view';
import { computed } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { computeJsonPath } from './bms-input-code.helper';

export interface Props extends FieldComponentProps {
  type: 'html' | 'json' | 'css' | 'javascript';
  modelValue: string;
  extraExtensions?: any[];
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: '',
  errors: () => [],
  captions: () => [],
  extraExtensions: () => [],
});

const input = defineModel({ type: String, default: '' });

const emit = defineEmits<{
  'update:modelValue': [value: string];
  'click-json-path': [path: string];
}>();

const jsonClickExtension = EditorView.domEventHandlers({
  click(event, view) {
    const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });
    if (pos === null) return;
    emit('click-json-path', computeJsonPath(view.state, pos));
  },
});

const extensions = computed<any[]>(() => {
  switch (props.type) {
    case 'html':
      return [html(), ...props.extraExtensions];
    case 'css':
      return [css(), ...props.extraExtensions];
    case 'javascript':
      return [javascript(), ...props.extraExtensions];
    default:
      return [
        json(),
        lintGutter(),
        linter(jsonParseLinter()),
        jsonClickExtension,
        ...props.extraExtensions,
      ];
  }
});
</script>

<style scoped lang="scss">
.code-mirror {
  max-height: 50rem;
  width: 100%;
  overflow: auto;
  border-radius: 4px;
}
</style>
