<script setup lang="ts">
import { computed, ref, watch } from 'vue';

import { ElButton, ElImage, ElInput, ElMessage } from 'element-plus';

import { api } from '#/api/request';
import { $t } from '#/locales';
import ChooseResource from '#/views/ai/resource/ChooseResource.vue';

import {
  buildWorkflowImageValueFromResource,
  buildWorkflowImageValueFromUpload,
  buildWorkflowImageValueFromUrl,
  formatWorkflowImageSize,
  getWorkflowImagePreviewUrl,
  normalizeWorkflowImageValue,
  validateWorkflowImageFile,
  WORKFLOW_IMAGE_LIMITS,
} from './workflowImageValue';

const props = defineProps({
  disabled: {
    type: Boolean,
    default: false,
  },
  modelValue: {
    type: [String, Object],
    default: undefined,
  },
});

const emit = defineEmits(['update:modelValue']);
const uploadLoading = ref(false);
const fileInputRef = ref<HTMLInputElement | null>(null);
const urlInput = ref('');

const currentImage = computed(() =>
  normalizeWorkflowImageValue(props.modelValue),
);
const previewUrl = computed(() => getWorkflowImagePreviewUrl(props.modelValue));

watch(
  () => props.modelValue,
  (value) => {
    const image = normalizeWorkflowImageValue(value);
    urlInput.value = image?.sourceType === 'url' ? image.url : '';
  },
  { immediate: true },
);

function applyUrl() {
  if (props.disabled) {
    return;
  }
  try {
    emit('update:modelValue', buildWorkflowImageValueFromUrl(urlInput.value));
  } catch (error: any) {
    ElMessage.error(error?.message || '图片 URL 无效');
  }
}

function triggerSelectFile() {
  if (!props.disabled && !uploadLoading.value) {
    fileInputRef.value?.click();
  }
}

async function handleNativeFileChange(event: Event) {
  const input = event.target as HTMLInputElement;
  const file = input.files?.[0];
  if (props.disabled || !file) {
    return;
  }
  uploadLoading.value = true;
  try {
    validateWorkflowImageFile(file);
    const response = await api.upload('/api/v1/commons/upload', { file }, {});
    if (props.disabled) {
      return;
    }
    emit(
      'update:modelValue',
      buildWorkflowImageValueFromUpload(file, response?.data?.path),
    );
  } catch (error: any) {
    ElMessage.error(error?.message || '图片上传失败');
    console.error('工作流图片上传失败', error);
  } finally {
    uploadLoading.value = false;
    input.value = '';
  }
}

function handleChooseResource(resource: any) {
  if (props.disabled) {
    return;
  }
  try {
    emit(
      'update:modelValue',
      buildWorkflowImageValueFromResource(resource || {}),
    );
  } catch (error: any) {
    ElMessage.error(error?.message || '图片素材选择失败');
  }
}

function clearImage() {
  if (props.disabled) {
    return;
  }
  urlInput.value = '';
  emit('update:modelValue', undefined);
}
</script>

<template>
  <div class="workflow-image-input">
    <input
      ref="fileInputRef"
      class="workflow-image-input__native"
      type="file"
      :accept="WORKFLOW_IMAGE_LIMITS.accept"
      :disabled="disabled"
      @change="handleNativeFileChange"
    />

    <div class="workflow-image-input__hint">
      支持 PNG、JPEG、WebP、GIF、BMP，单张不超过 10 MiB
    </div>

    <div v-if="currentImage" class="workflow-image-input__preview">
      <ElImage
        class="workflow-image-input__thumbnail"
        :src="previewUrl"
        fit="cover"
        :preview-src-list="previewUrl ? [previewUrl] : []"
        preview-teleported
      />
      <div class="workflow-image-input__summary">
        <div class="workflow-image-input__name">
          {{
            currentImage.sourceType === 'url'
              ? currentImage.url
              : currentImage.fileName
          }}
        </div>
        <div class="workflow-image-input__meta">
          {{
            currentImage.sourceType === 'url'
              ? '图片 URL'
              : formatWorkflowImageSize(currentImage.size) || '图片文件'
          }}
        </div>
      </div>
    </div>

    <ElInput
      v-model="urlInput"
      clearable
      :disabled="disabled"
      placeholder="输入 HTTP/HTTPS 图片 URL"
      @keyup.enter="applyUrl"
    >
      <template #append>
        <ElButton :disabled="disabled" @click="applyUrl">使用 URL</ElButton>
      </template>
    </ElInput>

    <div class="workflow-image-input__actions">
      <ElButton
        type="primary"
        plain
        :disabled="disabled"
        :loading="uploadLoading"
        @click="triggerSelectFile"
      >
        {{ currentImage ? '替换图片' : $t('button.upload') }}
      </ElButton>
      <ChooseResource
        attr-name="image"
        :disabled="disabled"
        :resource-type="0"
        @choose="handleChooseResource"
      />
      <ElButton
        v-if="currentImage && !disabled"
        text
        type="danger"
        @click="clearImage"
      >
        清空
      </ElButton>
    </div>
  </div>
</template>

<style scoped>
.workflow-image-input {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
}

.workflow-image-input__native {
  display: none;
}

.workflow-image-input__hint,
.workflow-image-input__meta {
  color: var(--el-text-color-secondary);
  font-size: 12px;
  line-height: 1.5;
}

.workflow-image-input__preview {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  border: 1px solid var(--el-border-color-light);
  border-radius: var(--el-border-radius-base);
  background: var(--el-fill-color-blank);
}

.workflow-image-input__thumbnail {
  width: 96px;
  height: 72px;
  flex: none;
  border-radius: var(--el-border-radius-small);
  background: var(--el-fill-color-light);
}

.workflow-image-input__summary {
  min-width: 0;
  flex: 1;
}

.workflow-image-input__name {
  overflow: hidden;
  color: var(--el-text-color-primary);
  font-size: 13px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.workflow-image-input__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
</style>
