<template>
  <div class="flex flex-col border-b border-[var(--wraith-border)] bg-[var(--wraith-bg-secondary)]" :style="{ height: editorHeight + 'px' }">
    <!-- Editor toolbar -->
    <div class="flex items-center justify-between px-3 py-1.5 border-b border-[var(--wraith-border)] shrink-0">
      <div class="flex items-center gap-2 text-xs min-w-0">
        <!-- File icon -->
        <svg class="w-3.5 h-3.5 text-[var(--wraith-text-muted)] shrink-0" viewBox="0 0 16 16" fill="currentColor">
          <path d="M3.75 1.5a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25V6H9.75A1.75 1.75 0 0 1 8 4.25V1.5H3.75zm5.75.56v2.19c0 .138.112.25.25.25h2.19L9.5 2.06zM2 1.75C2 .784 2.784 0 3.75 0h5.086c.464 0 .909.184 1.237.513l3.414 3.414c.329.328.513.773.513 1.237v8.086A1.75 1.75 0 0 1 12.25 15h-8.5A1.75 1.75 0 0 1 2 13.25V1.75z" />
        </svg>

        <span class="text-[var(--wraith-text-primary)] truncate font-mono text-[11px]">
          {{ filePath }}
        </span>

        <!-- Unsaved indicator -->
        <span v-if="hasUnsavedChanges" class="w-2 h-2 rounded-full bg-[var(--wraith-accent-yellow)] shrink-0" title="Unsaved changes" />
      </div>

      <div class="flex items-center gap-2 shrink-0">
        <!-- Save button -->
        <button
          class="px-3 py-1 text-xs rounded transition-colors cursor-pointer"
          :class="
            hasUnsavedChanges
              ? 'bg-[var(--wraith-accent-blue)] text-white hover:bg-blue-600'
              : 'bg-[var(--wraith-bg-tertiary)] text-[var(--wraith-text-muted)] cursor-not-allowed'
          "
          :disabled="!hasUnsavedChanges"
          @click="handleSave"
        >
          Save
        </button>

        <!-- Close button -->
        <button
          class="text-[var(--wraith-text-muted)] hover:text-[var(--wraith-accent-red)] transition-colors cursor-pointer"
          @click="emit('close')"
        >
          <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor">
            <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06z" />
          </svg>
        </button>
      </div>
    </div>

    <!-- CodeMirror container -->
    <div ref="editorRef" class="flex-1 min-h-0 overflow-hidden" />
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch } from "vue";
import { Call } from "@wailsio/runtime";

const SFTP = "github.com/vstockwell/wraith/internal/sftp.SFTPService";
import { EditorView, keymap, lineNumbers, highlightActiveLine, highlightSpecialChars } from "@codemirror/view";
import { EditorState } from "@codemirror/state";
import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
import { syntaxHighlighting, defaultHighlightStyle, bracketMatching } from "@codemirror/language";
import { oneDark } from "@codemirror/theme-one-dark";
import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";

const props = defineProps<{
  content: string;
  filePath: string;
  sessionId: string;
}>();

const emit = defineEmits<{
  close: [];
}>();

const editorRef = ref<HTMLElement | null>(null);
const hasUnsavedChanges = ref(false);
const editorHeight = ref(300);

let view: EditorView | null = null;

/** Detect language extension from file path. */
async function getLanguageExtension(path: string) {
  const ext = path.split(".").pop()?.toLowerCase() ?? "";
  switch (ext) {
    case "js":
    case "jsx":
    case "ts":
    case "tsx": {
      const { javascript } = await import("@codemirror/lang-javascript");
      return javascript({ jsx: ext.includes("x"), typescript: ext.startsWith("t") });
    }
    case "json": {
      const { json } = await import("@codemirror/lang-json");
      return json();
    }
    case "py": {
      const { python } = await import("@codemirror/lang-python");
      return python();
    }
    case "md":
    case "markdown": {
      const { markdown } = await import("@codemirror/lang-markdown");
      return markdown();
    }
    default:
      return null;
  }
}

onMounted(async () => {
  if (!editorRef.value) return;

  const langExt = await getLanguageExtension(props.filePath);

  const extensions = [
    lineNumbers(),
    highlightActiveLine(),
    highlightSpecialChars(),
    history(),
    bracketMatching(),
    closeBrackets(),
    syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
    oneDark,
    keymap.of([
      ...defaultKeymap,
      ...historyKeymap,
      ...closeBracketsKeymap,
    ]),
    EditorView.updateListener.of((update) => {
      if (update.docChanged) {
        hasUnsavedChanges.value = true;
      }
    }),
    EditorView.theme({
      "&": {
        height: "100%",
        fontSize: "13px",
      },
      ".cm-scroller": {
        overflow: "auto",
        fontFamily: "'JetBrains Mono', 'Cascadia Code', 'Fira Code', Menlo, Monaco, monospace",
      },
    }),
  ];

  if (langExt) {
    extensions.push(langExt);
  }

  const state = EditorState.create({
    doc: props.content,
    extensions,
  });

  view = new EditorView({
    state,
    parent: editorRef.value,
  });
});

onBeforeUnmount(() => {
  if (view) {
    view.destroy();
    view = null;
  }
});

// Re-create editor when content/filePath changes
watch(
  () => props.filePath,
  async () => {
    if (!view || !editorRef.value) return;
    hasUnsavedChanges.value = false;

    const langExt = await getLanguageExtension(props.filePath);
    const extensions = [
      lineNumbers(),
      highlightActiveLine(),
      highlightSpecialChars(),
      history(),
      bracketMatching(),
      closeBrackets(),
      syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
      oneDark,
      keymap.of([
        ...defaultKeymap,
        ...historyKeymap,
        ...closeBracketsKeymap,
      ]),
      EditorView.updateListener.of((update) => {
        if (update.docChanged) {
          hasUnsavedChanges.value = true;
        }
      }),
      EditorView.theme({
        "&": {
          height: "100%",
          fontSize: "13px",
        },
        ".cm-scroller": {
          overflow: "auto",
          fontFamily: "'JetBrains Mono', 'Cascadia Code', 'Fira Code', Menlo, Monaco, monospace",
        },
      }),
    ];

    if (langExt) {
      extensions.push(langExt);
    }

    view.destroy();

    const state = EditorState.create({
      doc: props.content,
      extensions,
    });

    view = new EditorView({
      state,
      parent: editorRef.value,
    });
  },
);

async function handleSave(): Promise<void> {
  if (!view || !hasUnsavedChanges.value) return;

  const currentContent = view.state.doc.toString();
  try {
    await Call.ByName(`${SFTP}.WriteFile`, props.sessionId, props.filePath, currentContent);
    hasUnsavedChanges.value = false;
  } catch (err) {
    console.error("Failed to save file:", err);
  }
}
</script>
