<template>
  <div class="input-area compact-input-area">
    <div class="stadium-input-wrapper" ref="stadiumShellOuter">
      <div
        class="stadium-shell"
        ref="compactInputShell"
        :class="{
          'is-multiline': inputIsMultiline,
          'is-focused': inputIsFocused,
          'has-text': (inputMessage || '').trim().length > 0
        }"
      >
        <input
          type="file"
          ref="fileUploadInput"
          class="file-input-hidden"
          multiple
          @change="onFileChange"
        />
        <div class="input-stack">
          <div v-if="selectedImages && selectedImages.length" class="image-inline-row">
            <div class="image-thumbnail-wrapper" v-for="img in selectedImages" :key="img">
              <img :src="getPreviewUrl(img)" :alt="formatImageName(img)" class="image-thumbnail" />
              <button
                type="button"
                class="image-remove-btn-hover"
                @click.stop="$emit('remove-image', img)"
              >
                ×
              </button>
            </div>
          </div>
          <div
            v-if="selectedVideos && selectedVideos.length"
            class="image-inline-row video-inline-row"
          >
            <div class="image-thumbnail-wrapper" v-for="video in selectedVideos" :key="video">
              <img
                :src="getPreviewUrl(video)"
                :alt="formatImageName(video)"
                class="image-thumbnail"
              />
              <button
                type="button"
                class="image-remove-btn-hover"
                @click.stop="$emit('remove-video', video)"
              >
                ×
              </button>
            </div>
          </div>
          <div class="input-row">
            <button
              type="button"
              class="stadium-btn add-btn"
              data-tutorial="quick-menu-open"
              @click.stop="$emit('toggle-quick-menu')"
              :disabled="!isConnected"
            >
              +
            </button>
            <textarea
              :key="composerInputKey"
              ref="stadiumInput"
              class="stadium-input"
              rows="1"
              :value="inputMessage"
              :disabled="!isConnected || streamingMessage || inputLocked"
              autocomplete="off"
              autocorrect="off"
              autocapitalize="off"
              placeholder="输入消息... (Ctrl+Enter 发送)"
              @input="onInput"
              @focus="$emit('input-focus')"
              @blur="$emit('input-blur')"
              @keydown.enter.ctrl.prevent="$emit('send-message')"
            ></textarea>
            <button
              type="button"
              class="stadium-btn send-btn"
              @click="$emit('send-or-stop')"
              :disabled="
                !isConnected ||
                (inputLocked && !streamingMessage) ||
                (mediaUploading && !streamingMessage) ||
                (!(inputMessage || '').trim() &&
                  !selectedImages?.length &&
                  !selectedVideos?.length &&
                  !streamingMessage)
              "
            >
              <span v-if="streamingMessage" class="stop-icon"></span>
              <span v-else class="send-icon"></span>
            </button>
          </div>
        </div>
      </div>
      <QuickMenu
        :open="quickMenuOpen"
        :is-connected="isConnected"
        :uploading="uploading"
        :streaming-message="streamingMessage"
        :thinking-mode="thinkingMode"
        :run-mode="runMode"
        :model-menu-open="modelMenuOpen"
        :model-options="modelOptions"
        :current-model-key="currentModelKey"
        :tool-menu-open="toolMenuOpen"
        :tool-settings="toolSettings"
        :tool-settings-loading="toolSettingsLoading"
        :settings-open="settingsOpen"
        :mode-menu-open="modeMenuOpen"
        :compressing="compressing"
        :current-conversation-id="currentConversationId"
        :icon-style="iconStyle"
        :tool-category-icon="toolCategoryIcon"
        :block-upload="blockUpload"
        :block-tool-toggle="blockToolToggle"
        :block-realtime-terminal="blockRealtimeTerminal"
        :block-focus-panel="blockFocusPanel"
        :block-token-panel="blockTokenPanel"
        :block-compress-conversation="blockCompressConversation"
        :block-conversation-review="blockConversationReview"
        @quick-upload="triggerQuickUpload"
        @pick-images="$emit('pick-images')"
        @pick-video="$emit('pick-video')"
        @toggle-tool-menu="$emit('toggle-tool-menu')"
        @toggle-settings="$emit('toggle-settings')"
        @toggle-mode-menu="$emit('toggle-mode-menu')"
        @select-run-mode="(mode) => $emit('select-run-mode', mode)"
        @toggle-model-menu="$emit('toggle-model-menu')"
        @select-model="(key) => $emit('select-model', key)"
        @update-tool-category="(id, enabled) => $emit('update-tool-category', id, enabled)"
        @realtime-terminal="$emit('realtime-terminal')"
        @toggle-focus-panel="$emit('toggle-focus-panel')"
        @toggle-token-panel="(val) => $emit('toggle-token-panel', val)"
        @compress-conversation="$emit('compress-conversation')"
        @toggle-approval-panel="$emit('toggle-approval-panel')"
        @open-review="$emit('open-review')"
      />
      <div class="permission-switcher" @click.stop>
        <button
          type="button"
          class="permission-switcher__btn"
          :disabled="!isConnected || streamingMessage"
          @click="$emit('open-versioning-dialog')"
        >
          <span>版本控制：{{ versioningEnabled ? '开启' : '关闭' }}</span>
        </button>
        <div class="permission-switcher__block">
          <button
            type="button"
            class="permission-switcher__btn"
            :disabled="!isConnected || streamingMessage"
            @click="$emit('toggle-permission-menu')"
          >
            <span>权限：{{ currentPermissionLabel }}</span>
            <span class="permission-switcher__caret" :class="{ open: permissionMenuOpen }">›</span>
          </button>
          <div v-if="permissionMenuOpen" class="permission-switcher__menu">
            <button
              v-for="option in permissionOptions"
              :key="option.value"
              type="button"
              class="permission-switcher__item"
              :class="{ active: option.value === currentPermissionMode }"
              @click="$emit('change-permission-mode', option.value)"
            >
              <span class="permission-switcher__item-label">{{ option.label }}</span>
              <span class="permission-switcher__item-desc">{{ option.description }}</span>
            </button>
          </div>
        </div>
      </div>
      <div class="context-usage-switcher" @click.stop>
        <button
          type="button"
          class="context-usage-switcher__btn"
          :disabled="!isConnected"
          @click="$emit('toggle-token-panel')"
        >
          <span
            class="context-usage-ring"
            :style="{
              '--context-progress': `${contextUsagePercent}%`,
              '--context-ring-color': contextUsageColor
            }"
            aria-hidden="true"
          >
            <span class="context-usage-ring__inner"></span>
          </span>
        </button>
        <div class="context-usage-switcher__tooltip">
          <div>{{ contextUsagePercentLabel }}已用</div>
          <div>{{ contextUsageCompactText }}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref, watch, nextTick, computed } from 'vue';
import QuickMenu from '@/components/input/QuickMenu.vue';
import { useInputStore } from '@/stores/input';
import { usePersonalizationStore } from '@/stores/personalization';

defineOptions({ name: 'InputComposer' });

const emit = defineEmits([
  'update:input-message',
  'input-change',
  'input-focus',
  'input-blur',
  'toggle-quick-menu',
  'send-message',
  'send-or-stop',
  'quick-upload',
  'pick-images',
  'pick-video',
  'toggle-tool-menu',
  'toggle-mode-menu',
  'toggle-model-menu',
  'select-run-mode',
  'select-model',
  'toggle-settings',
  'update-tool-category',
  'realtime-terminal',
  'toggle-focus-panel',
  'toggle-token-panel',
  'compress-conversation',
  'toggle-approval-panel',
  'file-selected',
  'remove-image',
  'remove-video',
  'open-review',
  'toggle-permission-menu',
  'change-permission-mode',
  'open-versioning-dialog'
]);

const props = defineProps<{
  inputMessage: string;
  inputIsMultiline: boolean;
  inputIsFocused: boolean;
  isConnected: boolean;
  streamingMessage: boolean;
  inputLocked: boolean;
  uploading: boolean;
  thinkingMode: boolean;
  runMode: 'fast' | 'thinking' | 'deep';
  quickMenuOpen: boolean;
  toolMenuOpen: boolean;
  modeMenuOpen: boolean;
  modelMenuOpen: boolean;
  toolSettings: Array<{ id: string; label: string; enabled: boolean }>;
  toolSettingsLoading: boolean;
  settingsOpen: boolean;
  compressing: boolean;
  currentConversationId: string | null;
  iconStyle: (key: string) => Record<string, string>;
  toolCategoryIcon: (categoryId: string) => string;
  modelOptions: Array<{
    key: string;
    label: string;
    description: string;
    disabled?: boolean;
    supportsImage?: boolean;
    supportsVideo?: boolean;
    contextWindow?: number | null;
  }>;
  currentModelKey: string;
  selectedImages?: string[];
  selectedVideos?: string[];
  mediaUploading?: boolean;
  blockUpload?: boolean;
  blockToolToggle?: boolean;
  blockRealtimeTerminal?: boolean;
  blockFocusPanel?: boolean;
  blockTokenPanel?: boolean;
  blockCompressConversation?: boolean;
  blockConversationReview?: boolean;
  currentPermissionMode: 'readonly' | 'approval' | 'unrestricted';
  permissionMenuOpen: boolean;
  permissionOptions: Array<{ value: string; label: string; description: string }>;
  currentContextTokens: number;
  versioningEnabled?: boolean;
}>();

const inputStore = useInputStore();
const personalizationStore = usePersonalizationStore();
const stadiumShellOuter = ref<HTMLElement | null>(null);
const compactInputShell = ref<HTMLElement | null>(null);
const stadiumInput = ref<HTMLTextAreaElement | null>(null);
const fileUploadInput = ref<HTMLInputElement | null>(null);

const formatImageName = (path: string): string => {
  if (!path) return '';
  const parts = path.split(/[/\\]/);
  return parts[parts.length - 1] || path;
};

const getPreviewUrl = (path: string): string => {
  if (!path) return '';
  return `/api/gui/files/download?path=${encodeURIComponent(path)}`;
};

const applyLineMetrics = (lines: number, multiline: boolean) => {
  inputStore.setInputLineCount(lines);
  inputStore.setInputMultiline(multiline);
};

const composerInputKey = computed(
  () => `${props.currentConversationId || 'new'}:${props.isConnected ? 'online' : 'offline'}`
);

const adjustTextareaSize = () => {
  const textarea = stadiumInput.value;
  if (!textarea) {
    return;
  }
  textarea.style.height = 'auto';
  const computedStyle = window.getComputedStyle(textarea);
  const lineHeight = parseFloat(computedStyle.lineHeight || '20') || 20;
  const maxHeight = lineHeight * 6;
  const targetHeight = Math.min(textarea.scrollHeight, maxHeight);
  const lines = Math.max(1, Math.round(targetHeight / lineHeight));
  const multiline = targetHeight > lineHeight * 1.4;
  applyLineMetrics(lines, multiline);
  textarea.style.height = `${targetHeight}px`;
};

const onInput = (event: Event) => {
  const target = event.target as HTMLTextAreaElement;
  if (!props.isConnected || props.streamingMessage || props.inputLocked) {
    target.value = props.inputMessage || '';
    return;
  }
  emit('update:input-message', target.value);
  emit('input-change');
  adjustTextareaSize();
};

const onFileChange = (event: Event) => {
  const target = event.target as HTMLInputElement;
  emit('file-selected', target?.files || null);
  if (target) {
    target.value = '';
  }
};

const triggerQuickUpload = () => {
  if (!props.isConnected || props.uploading) {
    return;
  }
  emit('quick-upload');
};

const currentPermissionLabel = computed(() => {
  const matched = (props.permissionOptions || []).find(
    (item) => item.value === props.currentPermissionMode
  );
  return matched ? matched.label : props.currentPermissionMode;
});

const modelContextWindow = computed(() => {
  const list = Array.isArray(props.modelOptions) ? props.modelOptions : [];
  const current = list.find((item) => item.key === props.currentModelKey);
  return Number(current?.contextWindow || 0);
});

const autoDeepCompressEnabled = computed(() => {
  return !!personalizationStore?.form?.auto_deep_compress_enabled;
});

const deepCompressLimit = computed(() => {
  const custom = Number(personalizationStore?.form?.deep_compress_trigger_tokens || 0);
  if (custom > 0) return custom;
  return 150000;
});

const contextUsageLimit = computed(() => {
  if (autoDeepCompressEnabled.value) {
    return deepCompressLimit.value;
  }
  if (modelContextWindow.value > 0) {
    return modelContextWindow.value;
  }
  return 0;
});

const contextUsagePercent = computed(() => {
  const limit = Number(contextUsageLimit.value || 0);
  if (limit <= 0) return 0;
  const current = Math.max(0, Number(props.currentContextTokens || 0));
  return Math.max(0, Math.min(100, (current / limit) * 100));
});

const contextUsagePercentLabel = computed(() => `${Math.round(contextUsagePercent.value)}%`);

const contextUsageColor = computed(() => {
  const percent = contextUsagePercent.value;
  if (percent < 40) return '#16a34a';
  if (percent <= 80) return '#f59e0b';
  return '#ef4444';
});

const formatCompactTokens = (value: number) => {
  const num = Math.max(0, Number(value || 0));
  if (num >= 1000) {
    const raw = num / 1000;
    const text = raw >= 100 ? Math.round(raw).toString() : raw.toFixed(1).replace(/\.0$/, '');
    return `${text}k`;
  }
  return `${Math.round(num)}`;
};

const contextUsageCompactText = computed(() => {
  const current = formatCompactTokens(props.currentContextTokens || 0);
  const limit = Number(contextUsageLimit.value || 0);
  if (limit <= 0) return `${current}/--`;
  return `${current}/${formatCompactTokens(limit)}`;
});

defineExpose({
  stadiumShellOuter,
  compactInputShell,
  stadiumInput,
  fileUploadInput
});

watch(
  () => props.inputMessage,
  async () => {
    await nextTick();
    adjustTextareaSize();
  }
);

watch(
  () => props.isConnected,
  async (connected) => {
    if (!connected && stadiumInput.value) {
      stadiumInput.value.blur();
    }
    await nextTick();
    adjustTextareaSize();
  }
);

onMounted(() => {
  adjustTextareaSize();
});
</script>

<style scoped>
.image-inline-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 4px 10px 2px;
  line-height: 1.4;
}

.image-thumbnail-wrapper {
  position: relative;
  width: 60px;
  height: 60px;
  border-radius: 6px;
  overflow: hidden;
  cursor: pointer;
  border: 1px solid var(--border-color, #2a2f3a);
}

.image-thumbnail {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.image-remove-btn-hover {
  position: absolute;
  top: 0;
  right: 0;
  background: none;
  color: #fff;
  border: none;
  font-size: 20px;
  font-weight: bold;
  line-height: 1;
  cursor: pointer;
  display: none;
  padding: 2px 4px;
  text-shadow: 0 0 3px rgba(0, 0, 0, 0.8);
  transition: color 0.15s ease;
}

.image-thumbnail-wrapper:hover .image-remove-btn-hover {
  display: block;
}

.image-remove-btn-hover:hover {
  color: #ef4444;
}

</style>
