<script setup lang="ts">
import { ref, computed, nextTick } from "vue";
import { apiGet, transcribeAudio } from "@/api/client";
import { useVoiceRecorder } from "@/composables/useVoiceRecorder";
import { useChatStore } from "@/stores/chat";
import { useSettingsStore } from "@/stores/settings";
import type { Note } from "@/types/note";

const emit = defineEmits<{
  submit: [payload: { content: string; contextNoteId?: number }];
}>();

const store = useChatStore();

const messageInput = ref("");
const inputEl = ref<HTMLTextAreaElement | null>(null);

// Note picker state
const attachedNote = ref<{ id: number; title: string } | null>(null);
const showNotePicker = ref(false);
const noteSearchQuery = ref("");
const noteSearchResults = ref<{ id: number; title: string }[]>([]);
const noteSearchLoading = ref(false);
let noteSearchTimer: ReturnType<typeof setTimeout> | null = null;

function onSubmit() {
  const content = messageInput.value.trim();
  if (!content) return;
  emit("submit", {
    content,
    contextNoteId: attachedNote.value?.id,
  });
  messageInput.value = "";
  attachedNote.value = null;
  resetTextareaHeight();
}

function onInputKeydown(e: KeyboardEvent) {
  if (e.key === "Enter" && !e.shiftKey) {
    e.preventDefault();
    onSubmit();
  }
}

function autoResize() {
  const el = inputEl.value;
  if (!el) return;
  el.style.height = "auto";
  el.style.height = Math.min(el.scrollHeight, 120) + "px";
}

function resetTextareaHeight() {
  const el = inputEl.value;
  if (!el) return;
  el.style.height = "auto";
}

// Note picker
function toggleNotePicker() {
  showNotePicker.value = !showNotePicker.value;
  if (showNotePicker.value) {
    noteSearchQuery.value = "";
    noteSearchResults.value = [];
    nextTick(() => {
      const el = document.querySelector(
        ".dashboard-chat .note-picker-search"
      ) as HTMLInputElement;
      el?.focus();
    });
  }
}

function onNoteSearchInput() {
  if (noteSearchTimer) clearTimeout(noteSearchTimer);
  noteSearchTimer = setTimeout(async () => {
    const q = noteSearchQuery.value.trim();
    if (!q) {
      noteSearchResults.value = [];
      return;
    }
    noteSearchLoading.value = true;
    try {
      const data = await apiGet<{ notes: Note[] }>(
        `/api/notes?q=${encodeURIComponent(q)}&all=true&limit=5`
      );
      noteSearchResults.value = data.notes.map((n) => ({
        id: n.id,
        title: n.title,
      }));
    } catch {
      noteSearchResults.value = [];
    } finally {
      noteSearchLoading.value = false;
    }
  }, 250);
}

function selectNote(note: { id: number; title: string }) {
  attachedNote.value = note;
  showNotePicker.value = false;
}

function removeAttachedNote() {
  attachedNote.value = null;
}

function focus() {
  inputEl.value?.focus();
}

// Voice PTT
const settingsStore = useSettingsStore();
const voiceEnabled = computed(() => settingsStore.voiceSttReady);
const transcribingVoice = ref(false);
const recorder = useVoiceRecorder();

async function startPtt() {
  if (!voiceEnabled.value || recorder.recording.value) return;
  await recorder.startRecording();
}

async function stopPtt() {
  if (!recorder.recording.value) return;
  transcribingVoice.value = true;
  try {
    const blob = await recorder.stopRecording();
    const { transcript } = await transcribeAudio(blob);
    if (transcript.trim()) {
      messageInput.value = (messageInput.value ? messageInput.value + " " : "") + transcript.trim();
      await nextTick();
      autoResize();
    }
  } catch { /* transcription failed silently */ } finally {
    transcribingVoice.value = false;
  }
}

defineExpose({ focus });
</script>

<template>
  <div class="dashboard-chat">
    <!-- Attached note pill -->
    <div v-if="attachedNote" class="attached-note">
      <span class="attached-note-pill">
        {{ attachedNote.title }}
        <button class="attached-note-remove" aria-label="Remove attached note" @click="removeAttachedNote">
          &times;
        </button>
      </span>
    </div>

    <div class="chat-input-bar">
      <div class="note-picker-wrapper">
        <button
          class="btn-attach"
          @click="toggleNotePicker"
          :disabled="!store.chatReady"
          title="Attach a note"
        >
          <svg
            width="18"
            height="18"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
          >
            <path
              d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48"
            />
          </svg>
        </button>

        <div v-if="showNotePicker" class="note-picker-dropdown">
          <input
            class="note-picker-search"
            v-model="noteSearchQuery"
            @input="onNoteSearchInput"
            placeholder="Search notes..."
          />
          <div class="note-picker-results">
            <div
              v-for="note in noteSearchResults"
              :key="note.id"
              class="note-picker-item"
              @click="selectNote(note)"
            >
              {{ note.title || "Untitled" }}
            </div>
            <div v-if="noteSearchLoading" class="note-picker-empty">
              Searching...
            </div>
            <div
              v-else-if="noteSearchQuery && !noteSearchResults.length"
              class="note-picker-empty"
            >
              No notes found
            </div>
          </div>
        </div>
      </div>

      <textarea
        ref="inputEl"
        v-model="messageInput"
        @keydown="onInputKeydown"
        @input="autoResize"
        :placeholder="
          !store.chatReady ? 'Chat unavailable'
          : store.streaming ? 'Type to queue… (Enter to queue)'
          : 'Start a new chat… (Enter to send)'
        "
        :disabled="!store.chatReady"
        rows="1"
      ></textarea>

      <button
        v-if="voiceEnabled && recorder.isSupported"
        class="btn-attach btn-mic-ptt"
        :class="{ 'mic-recording': recorder.recording.value, 'mic-transcribing': transcribingVoice }"
        @mousedown.prevent="startPtt"
        @mouseup.prevent="stopPtt"
        @touchstart.prevent="startPtt"
        @touchend.prevent="stopPtt"
        :disabled="transcribingVoice || !store.chatReady"
        :title="recorder.recording.value ? 'Release to send' : 'Hold to speak'"
        aria-label="Push to talk"
      >
        <svg v-if="!transcribingVoice" width="17" height="17" viewBox="0 0 24 24" fill="currentColor">
          <path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm-1-9c0-.55.45-1 1-1s1 .45 1 1v6c0 .55-.45 1-1 1s-1-.45-1-1V5zm6 6c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/>
        </svg>
        <svg v-else width="17" height="17" viewBox="0 0 24 24" fill="currentColor">
          <circle cx="12" cy="12" r="8" opacity="0.35"/>
          <circle cx="12" cy="12" r="4"/>
        </svg>
      </button>

      <button
        class="btn-send"
        @click="onSubmit"
        :disabled="!messageInput.trim() || !store.chatReady"
      >
        &uarr;
      </button>
    </div>
  </div>
</template>

<style scoped>
.dashboard-chat {
  margin-top: 0.75rem;
}

.attached-note {
  padding: 0.25rem 0;
}
.attached-note-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  background: var(--color-primary);
  color: #fff;
  border-radius: 12px;
  padding: 0.2rem 0.5rem;
  font-size: 0.8rem;
}
.attached-note-remove {
  background: none;
  border: none;
  color: rgba(255, 255, 255, 0.7);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 0 0.15rem;
}
.attached-note-remove:hover {
  color: #fff;
}

.chat-input-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.5rem 0.5rem 0.75rem;
  background: var(--color-input-bar-bg);
  border-radius: 20px;
  box-shadow: 0 2px 12px var(--color-shadow);
}

.chat-input-bar textarea {
  flex: 1;
  resize: none;
  padding: 0.4rem 0.5rem;
  border: none;
  border-radius: 12px;
  font-family: inherit;
  font-size: 0.95rem;
  background: transparent;
  color: var(--color-input-bar-text);
  outline: none;
  max-height: 120px;
  overflow-y: auto;
}
.chat-input-bar textarea::placeholder {
  color: var(--color-input-bar-placeholder);
}
.chat-input-bar textarea:disabled {
  opacity: 0.5;
}

/* Note picker */
.note-picker-wrapper {
  position: relative;
}
.btn-attach {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-input-bar-text);
  opacity: 0.6;
  padding: 0.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
}
.btn-attach:hover {
  opacity: 1;
}
.btn-attach:disabled {
  opacity: 0.3;
  cursor: default;
}
.note-picker-dropdown {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  width: 280px;
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 4px 16px var(--color-shadow);
  z-index: 10;
  overflow: hidden;
}
.note-picker-search {
  width: 100%;
  padding: 0.5rem 0.75rem;
  border: none;
  border-bottom: 1px solid var(--color-border);
  background: transparent;
  color: var(--color-text);
  font-size: 0.9rem;
  outline: none;
  font-family: inherit;
  box-sizing: border-box;
}
.note-picker-results {
  max-height: 200px;
  overflow-y: auto;
}
.note-picker-item {
  padding: 0.5rem 0.75rem;
  cursor: pointer;
  font-size: 0.9rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.note-picker-item:hover {
  background: var(--color-bg-secondary);
}
.note-picker-empty {
  padding: 0.5rem 0.75rem;
  color: var(--color-text-muted);
  font-size: 0.85rem;
}

.btn-send {
  width: 34px;
  min-width: 34px;
  height: 34px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-primary);
  color: #fff;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  font-size: 1.1rem;
  flex-shrink: 0;
}
.btn-send:disabled {
  opacity: 0.35;
  cursor: default;
}

.btn-mic-ptt {
  transition: color 0.15s, opacity 0.15s;
}
.btn-mic-ptt.mic-recording {
  color: #ef4444;
  opacity: 1;
}
.btn-mic-ptt.mic-transcribing {
  color: var(--color-primary);
  opacity: 1;
}
</style>
