<template>
  <view class="files-wrap">
    <view class="files-label">
      {{ name }}<text v-if="required" class="form-cell-required">*</text>
    </view>
    <view class="grid">
      <view v-for="(f, idx) in files" :key="idx" class="item" @click="preview(idx)">
        <image class="thumb" :src="f.url" mode="aspectFill" />
        <view class="remove" @click.stop="remove(idx)">×</view>
      </view>
      <view class="add" @click="add">
        <view class="plus">+</view>
      </view>
    </view>
  </view>
</template>

<script setup>
import { computed } from 'vue';
import { chooseAndUploadImage, normalizeFileUrl } from '@/utils/file';
import { toast } from '@/utils/widget';

const emits = defineEmits(['change']);
const props = defineProps({
  form: { type: Object, default: () => ({}) },
  name: { default: '' },
  required: { type: Boolean, default: false },
  title: { default: '' },
  disableChange: { type: Boolean, default: false },
  max: { type: [Number, String], default: 9 },
});

const maxCount = computed(() => {
  const n = Number(props.max);
  return Number.isFinite(n) && n > 0 ? Math.min(n, 9) : 9;
});

const files = computed(() => {
  const v = props.form?.[props.title];
  if (Array.isArray(v)) {
    return v
      .map((i) => {
        if (typeof i === 'string') return { url: normalizeFileUrl(i), name: getFileNameFromUrl(i) };
        if (i && typeof i === 'object' && i.url) {
          const url = normalizeFileUrl(String(i.url));
          return {
            ...i,
            url,
            name: i.name || i.fileName || getFileNameFromUrl(url),
          };
        }
        return null;
      })
      .filter(Boolean);
  }
  if (typeof v === 'string' && v) {
    const url = normalizeFileUrl(v);
    return [{ url, name: getFileNameFromUrl(url) }];
  }
  return [];
});

function emitValue(list) {
  emits('change', { title: props.title, value: list });
}

function preview(idx) {
  const urls = files.value.map((i) => i.url);
  if (!urls.length) return;
  uni.previewImage({ urls, current: urls[idx] });
}

function remove(idx) {
  if (props.disableChange) return;
  const next = files.value.filter((_, i) => i !== idx);
  emitValue(next);
}

async function add() {
  if (props.disableChange) return;
  if (files.value.length >= maxCount.value) {
    toast(`最多上传${maxCount.value}张`);
    return;
  }
  const url = await chooseAndUploadImage({ count: 1 });
  if (!url) return;
  emitValue([...files.value, { url, name: getFileNameFromUrl(url) }]);
}

function getFileNameFromUrl(url) {
  const cleanUrl = String(url || '').split('?')[0].split('#')[0];
  const rawName = cleanUrl.split('/').pop() || '';
  if (!rawName) return '';

  let fileName = rawName;
  try {
    fileName = decodeURIComponent(rawName);
  } catch (error) {
    fileName = rawName;
  }
  return fileName.replace(/^\d{10,}[-_]/, '');
}
</script>

<style lang="scss" scoped>
@import '../cell-style.css';

.files-wrap {
  padding: 24rpx 30rpx;
  border-bottom: 1px solid #eee;
  background: #fff;
}

.files-label {
  font-size: 30rpx;
  line-height: 42rpx;
}

.grid {
  margin-top: 18rpx;
  display: flex;
  flex-wrap: wrap;
  gap: 18rpx;
}

.item {
  width: 160rpx;
  height: 160rpx;
  border-radius: 10rpx;
  overflow: hidden;
  position: relative;
  background: #f6f6f6;
}

.thumb {
  width: 100%;
  height: 100%;
}

.remove {
  position: absolute;
  top: 6rpx;
  right: 6rpx;
  width: 36rpx;
  height: 36rpx;
  line-height: 36rpx;
  text-align: center;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  border-radius: 18rpx;
  font-size: 30rpx;
}

.add {
  width: 160rpx;
  height: 160rpx;
  border-radius: 10rpx;
  border: 1px dashed #cfcfcf;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #999;
}

.plus {
  font-size: 58rpx;
  line-height: 56rpx;
}
</style>
