<script setup lang="ts">
import { ref } from 'vue';
import { ElMessage } from 'element-plus';
import { useAdminLocale } from '../composables/useAdminLocale';
import api from '../api';
import { fetchMediaLibraryImages } from '../utils/media-library';
import { resolveApiError } from '../i18n/form-validation';

const props = withDefaults(
  defineProps<{
    modelValue: string;
    category?: string;
    sizeHintKey?: string;
    disabled?: boolean;
  }>(),
  { category: 'contents', sizeHintKey: 'content.upload.cover_size_hint' },
);

const emit = defineEmits<{ 'update:modelValue': [string] }>();

const { t } = useAdminLocale();

const IMAGE_ACCEPT = 'image/png,image/jpeg,image/webp,image/gif,image/svg+xml';
const MAX_UPLOAD_SIZE = 5 * 1024 * 1024;

const uploading = ref(false);
const mediaPickerVisible = ref(false);
const mediaFiles = ref<Array<{ id: string; filename: string; url: string; mimeType: string; category?: string }>>([]);
const mediaLoading = ref(false);

async function uploadImage(file: File) {
  if (file.size > MAX_UPLOAD_SIZE) {
    ElMessage.error(t('content.upload.size_error'));
    return;
  }
  uploading.value = true;
  try {
    const fd = new FormData();
    fd.append('file', file);
    const { data } = await api.post(`/admin/uploads?category=${props.category}`, fd, {
      headers: { 'Content-Type': 'multipart/form-data' },
    });
    const url = data.data?.url as string;
    if (url) {
      emit('update:modelValue', url);
      ElMessage.success(t('content.upload.success'));
    }
  } catch (err: unknown) {
    const e = err as { response?: { data?: { message?: string } } };
    ElMessage.error(String(e.response?.data?.message || t('content.upload.failed')));
  } finally {
    uploading.value = false;
  }
}

function onFileChange(e: Event) {
  const input = e.target as HTMLInputElement;
  if (input.files?.[0]) {
    void uploadImage(input.files[0]);
    input.value = '';
  }
}

function removeImage() {
  emit('update:modelValue', '');
}

async function openMediaPicker() {
  mediaPickerVisible.value = true;
  mediaLoading.value = true;
  try {
    mediaFiles.value = await fetchMediaLibraryImages({ pageSize: 200 });
  } catch (err: unknown) {
    mediaFiles.value = [];
    ElMessage.error(resolveApiError(err, t, 'content.upload.load_media_failed'));
  } finally {
    mediaLoading.value = false;
  }
}

function pickMediaFile(url: string) {
  emit('update:modelValue', url);
  mediaPickerVisible.value = false;
}
</script>

<template>
  <div class="content-image-field">
    <div class="field-main">
      <div v-if="modelValue" class="preview">
        <img :src="modelValue" alt="" class="preview-img" />
        <button
          type="button"
          class="preview-remove"
          :title="t('content.upload.remove')"
          :disabled="disabled || uploading"
          @click="removeImage"
        >
          &times;
        </button>
      </div>
      <div class="field-controls">
        <p v-if="sizeHintKey" class="size-hint">{{ t(sizeHintKey) }}</p>
        <div class="actions">
          <label class="upload-btn" :class="{ 'is-uploading': uploading, 'is-disabled': disabled }">
            <input
              type="file"
              :accept="IMAGE_ACCEPT"
              style="display: none"
              :disabled="disabled || uploading"
              @change="onFileChange"
            />
            {{ uploading ? t('content.upload.uploading') : t('content.upload.upload_btn') }}
          </label>
          <button type="button" class="pick-btn" :disabled="disabled || uploading" @click="openMediaPicker">
            {{ t('content.upload.pick_media') }}
          </button>
        </div>
      </div>
    </div>
    <el-input
      :model-value="modelValue"
      :placeholder="t('content.upload.url_placeholder')"
      size="small"
      :disabled="disabled"
      @update:model-value="emit('update:modelValue', $event)"
    />
  </div>

  <el-dialog
    v-model="mediaPickerVisible"
    :title="t('content.upload.pick_media_title')"
    width="680px"
    destroy-on-close
    append-to-body
    :z-index="4000"
  >
    <div v-if="mediaLoading" class="media-state">{{ t('common.loading') }}</div>
    <div v-else-if="mediaFiles.length === 0" class="media-state">{{ t('content.upload.no_media') }}</div>
    <div v-else class="media-grid">
      <div
        v-for="file in mediaFiles"
        :key="file.id"
        class="media-card"
        @click="pickMediaFile(file.url)"
      >
        <div class="media-thumb">
          <img v-if="file.mimeType !== 'image/svg+xml'" :src="file.url" :alt="file.filename" loading="lazy" />
          <div v-else class="media-svg">SVG</div>
        </div>
        <div class="media-name" :title="file.filename">{{ file.filename }}</div>
        <div v-if="file.category" class="media-category">{{ file.category }}</div>
      </div>
    </div>
  </el-dialog>
</template>

<style scoped>
.content-image-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
}

.field-main {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.field-controls {
  flex: 1;
  min-width: 0;
}

.size-hint {
  margin: 0 0 4px;
  font-size: 11px;
  line-height: 1.35;
  color: var(--text-muted);
}

.preview {
  position: relative;
  flex-shrink: 0;
  width: 120px;
  max-width: 120px;
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: #f4f0e8;
}

.preview-img {
  width: 100%;
  max-height: 68px;
  display: block;
  object-fit: contain;
}

.preview-remove {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: rgba(31, 35, 32, 0.78);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.36);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}

.preview-remove:hover {
  background: rgba(159, 47, 45, 0.92);
}

.actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.upload-btn,
.pick-btn {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 6px;
  font-size: 11px;
  font-family: inherit;
  font-weight: 700;
  cursor: pointer;
}

.upload-btn {
  border: 1px solid var(--primary);
  background: var(--primary);
  color: #fff;
}

.upload-btn.is-uploading,
.upload-btn.is-disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.pick-btn {
  border: 1px solid var(--border);
  background: #fff;
  color: var(--text);
}

.pick-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.media-state {
  text-align: center;
  padding: 40px 0;
  color: var(--text-muted);
}

.media-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 12px;
  max-height: 420px;
  overflow-y: auto;
}

.media-card {
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  background: #fff;
}

.media-card:hover {
  border-color: #d5cfc3;
  box-shadow: 0 8px 22px rgba(56, 49, 37, 0.08);
}

.media-thumb {
  height: 80px;
  background: #f4f0e8;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.media-thumb img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.media-svg {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-muted);
}

.media-name {
  padding: 6px 8px 2px;
  font-size: 11px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.media-category {
  padding: 0 8px 6px;
  font-size: 10px;
  color: var(--text-muted);
  opacity: 0.85;
}
</style>
