<template>
  <view class="attachment-block">
    <view class="form-item clickable-item" @click="handleChooseFiles">
      <view class="form-icon">{{ icon }}</view>
      <text class="form-label">{{ title }}</text>
      <text class="arrow">›</text>
    </view>

    <view class="images-preview" v-if="imageFiles.length">
      <view
        class="image-item"
        v-for="(file, index) in imageFiles"
        :key="(file.uid || file.path) + index"
      >
        <image
          :src="file.path"
          mode="aspectFill"
          class="preview-image"
          @click="previewImage(index)"
        />
        <view class="remove-btn" @click.stop="removeFile(file)">✕</view>
      </view>
    </view>

    <view class="files-list" v-if="otherFiles.length">
      <view
        class="file-item"
        v-for="(file, index) in otherFiles"
        :key="(file.uid || file.path) + index"
        @click="previewFile(file)"
      >
        <text class="file-type-badge" :class="getFileTypeClass(file.name)">
          {{ getFileTypeLabel(file.name) }}
        </text>
        <view class="file-info">
          <text class="file-name">{{ file.name }}</text>
          <text class="file-size" v-if="file.size > 0">{{ formatFileSize(file.size) }}</text>
        </view>
        <view class="file-icon">{{ getFileIcon(file.name) }}</view>
        <view class="remove-btn" @click.stop="removeFile(file)">✕</view>
      </view>
    </view>
  </view>
</template>

<script setup>
import { computed } from 'vue';
import { batchUploadFilesToQiniu } from '@/utils/qiniu.js';

const props = defineProps({
  modelValue: {
    type: Array,
    default: () => []
  },
  maxCount: {
    type: Number,
    default: 5
  },
  title: {
    type: String,
    default: '添加文件'
  },
  icon: {
    type: String,
    default: '📄'
  },
  extensions: {
    type: Array,
    default: () => ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.txt', '.zip', '.rar', '.jpg', '.png']
  }
});

const emit = defineEmits(['update:modelValue', 'change']);

const files = computed({
  get: () => props.modelValue,
  set: (val) => {
    emit('update:modelValue', val);
    emit('change', val);
  }
});

const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic', 'heif', 'svg'];

const isImageFile = (file) => {
  if (!file) return false;
  const ext = getFileExtension(file.name);
  return imageExtensions.includes(ext);
};

const imageFiles = computed(() => files.value.filter((file) => isImageFile(file)));
const otherFiles = computed(() => files.value.filter((file) => !isImageFile(file)));

const handleChooseFiles = async () => {
  const remainingCount = props.maxCount - files.value.length;
  if (remainingCount <= 0) {
    uni.showToast({
      title: `最多只能添加${props.maxCount}个文件`,
      icon: 'none'
    });
    return;
  }

  try {
    // #ifdef APP-PLUS
    await chooseFilesNative(remainingCount);
    // #endif

    // #ifndef APP-PLUS
    await chooseFilesWithUni(remainingCount);
    // #endif
  } catch (error) {
    console.error('选择文件失败:', error);
    uni.showToast({
      title: error?.message || '选择文件失败',
      icon: 'none'
    });
  }
};

const chooseFilesWithUni = (remainingCount) => {
  return new Promise((resolve, reject) => {
    uni.chooseFile({
      count: remainingCount,
      extension: props.extensions,
      success: async (res) => {
        try {
          await uploadFiles(res.tempFiles.map((file) => ({
            path: file.path,
            name: file.name,
            size: file.size || 0
          })));
          resolve();
        } catch (error) {
          reject(error);
        }
      },
      fail: () => {
        reject(new Error('文件选择被取消或失败'));
      }
    });
  });
};

const chooseFilesNative = async (remainingCount) => {
  if (typeof plus === 'undefined') {
    uni.showToast({
      title: '当前环境不支持文件选择',
      icon: 'none'
    });
    throw new Error('native file picker not available');
  }

  return new Promise((resolve, reject) => {
    try {
      const Intent = plus.android.importClass('android.content.Intent');
      const main = plus.android.runtimeMainActivity();
      const intent = new Intent(Intent.ACTION_GET_CONTENT);
      intent.setType('*/*');
      intent.addCategory(Intent.CATEGORY_OPENABLE);
      intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

      const originalOnActivityResult = main.onActivityResult;
      main.startActivityForResult(intent, 1001);

      main.onActivityResult = async (requestCode, resultCode, data) => {
        if (requestCode === 1001) {
          if (resultCode === -1 && data) {
            try {
              const filesToUpload = extractFilesFromIntent(data, main, remainingCount);
              if (filesToUpload.length) {
                await uploadFiles(filesToUpload);
              }
              cleanup();
              resolve();
            } catch (error) {
              cleanup();
              reject(error);
            }
          } else {
            cleanup();
            reject(new Error('用户取消选择'));
          }
        } else {
          cleanup();
          reject(new Error('无效的请求'));
        }
      };

      const cleanup = () => {
        if (originalOnActivityResult) {
          main.onActivityResult = originalOnActivityResult;
        }
      };
    } catch (error) {
      reject(error);
    }
  });
};

const extractFilesFromIntent = (data, main, remainingCount) => {
  const clipData = data.getClipData();
  const filesToUpload = [];

  const getFileName = (uri) => {
    try {
      const cursor = main.getContentResolver().query(uri, null, null, null, null);
      if (cursor && cursor.moveToFirst()) {
        const nameIndex = cursor.getColumnIndex('_display_name');
        if (nameIndex !== -1) {
          const fileName = cursor.getString(nameIndex);
          cursor.close();
          return fileName;
        }
        cursor.close();
      }
    } catch (e) {
      console.error('获取文件名失败:', e);
    }
    return `file_${Date.now()}`;
  };

  if (clipData) {
    const count = clipData.getItemCount();
    for (let i = 0; i < count && filesToUpload.length < remainingCount; i++) {
      const item = clipData.getItemAt(i);
      const uri = item.getUri();
      const uriString = uri.toString();
      const fileName = getFileName(uri);
      filesToUpload.push({
        name: fileName,
        path: uriString,
        size: 0
      });
    }
  } else {
    const uri = data.getData();
    if (uri) {
      const uriString = uri.toString();
      const fileName = getFileName(uri);
      filesToUpload.push({
        name: fileName,
        path: uriString,
        size: 0
      });
    }
  }

  return filesToUpload;
};

const uploadFiles = async (fileList) => {
  if (!fileList.length) return;

  try {
    uni.showLoading({
      title: '上传中...',
      mask: true
    });

    const uploadResults = await batchUploadFilesToQiniu(fileList);
    const newFiles = uploadResults.map(result => ({
      name: result.name,
      path: result.url,
      size: result.size || 0
    }));

    files.value = [...files.value, ...newFiles];
    uni.showToast({
      title: `成功添加${newFiles.length}个文件`,
      icon: 'success'
    });
  } catch (error) {
    console.error('上传文件失败:', error);
    uni.showToast({
      title: error?.message || '上传文件失败',
      icon: 'none'
    });
    throw error;
  } finally {
    uni.hideLoading();
  }
};

const removeFile = (file) => {
  const next = files.value.filter((item) => item !== file);
  files.value = next;
};

const getFileExtension = (fileName = '') => {
  if (!fileName) return '';
  return fileName.split('.').pop().toLowerCase();
};

const getFileIcon = (fileName) => {
  const ext = getFileExtension(fileName);
  const iconMap = {
    pdf: '📕',
    doc: '📘',
    docx: '📘',
    xls: '📗',
    xlsx: '📗',
    ppt: '📙',
    pptx: '📙',
    txt: '📄',
    zip: '📦',
    rar: '📦',
    jpg: '🖼️',
    jpeg: '🖼️',
    png: '🖼️',
    gif: '🖼️'
  };
  return iconMap[ext] || '📄';
};

const getFileTypeKey = (fileName) => {
  const ext = getFileExtension(fileName);
  if (!ext) return 'other';
  if (imageExtensions.includes(ext)) return 'image';
  if (['pdf'].includes(ext)) return 'pdf';
  if (['doc', 'docx', 'wps'].includes(ext)) return 'doc';
  if (['xls', 'xlsx', 'csv'].includes(ext)) return 'xls';
  if (['ppt', 'pptx'].includes(ext)) return 'ppt';
  if (['zip', 'rar', '7z'].includes(ext)) return 'zip';
  return 'other';
};

const getFileTypeLabel = (fileName) => {
  const type = getFileTypeKey(fileName);
  const labelMap = {
    image: 'IMG',
    pdf: 'PDF',
    doc: 'DOC',
    xls: 'XLS',
    ppt: 'PPT',
    zip: 'ZIP',
    other: 'FILE'
  };
  return labelMap[type] || 'FILE';
};

const getFileTypeClass = (fileName) => {
  return `badge-${getFileTypeKey(fileName)}`;
};

const formatFileSize = (bytes) => {
  if (!bytes || bytes === 0) return '';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
};

const previewImage = (index) => {
  const urls = imageFiles.value.map((file) => file.path);
  if (!urls.length) return;
  uni.previewImage({
    urls,
    current: urls[index] || urls[0]
  });
};

const previewFile = (file) => {
  if (!file?.path) {
    uni.showToast({
      title: '文件路径不存在',
      icon: 'none'
    });
    return;
  }

  const ext = getFileExtension(file.name);
  if (imageExtensions.includes(ext)) {
    previewImage(imageFiles.value.findIndex((item) => item === file));
    return;
  }

  // #ifdef H5
  window.open(file.path, '_blank');
  // #endif

  // #ifdef APP-PLUS
  plus.runtime.openURL(file.path);
  // #endif

  // #ifndef H5 || APP-PLUS
  uni.showToast({
    title: '点击下载文件',
    icon: 'none'
  });
  uni.downloadFile({
    url: file.path,
    success: (res) => {
      if (res.statusCode === 200) {
        uni.openDocument({
          filePath: res.tempFilePath,
          success: () => {
            console.log('打开文档成功');
          },
          fail: (err) => {
            console.error('打开文档失败:', err);
            uni.showToast({
              title: '无法打开此文件',
              icon: 'none'
            });
          }
        });
      }
    },
    fail: (err) => {
      console.error('下载文件失败:', err);
      uni.showToast({
        title: '下载文件失败',
        icon: 'none'
      });
    }
  });
  // #endif
};
</script>

<style scoped lang="scss">
.attachment-block {
  margin-bottom: 12px;
}

.form-item {
  display: flex;
  align-items: center;
  padding: 16px;
  background-color: #fff;
  border-radius: 8px;
  gap: 12px;
}

.clickable-item {
  cursor: pointer;

  &:active {
    background-color: #f5f5f5;
  }
}

.form-icon {
  font-size: 20px;
  flex-shrink: 0;
}

.form-label {
  flex: 1;
  font-size: 15px;
  color: #333;
}

.arrow {
  font-size: 20px;
  color: #999;
  flex-shrink: 0;
}

.files-list {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.file-item {
  display: flex;
  align-items: center;
  padding: 12px;
  background-color: #fff;
  border-radius: 8px;
  margin-bottom: 8px;
  gap: 12px;

  &:active {
    background-color: #f5f5f5;
  }
}

.file-info {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.file-name {
  font-size: 14px;
  color: #333;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
}

.file-size {
  font-size: 12px;
  color: #999;
}

.remove-btn {
  width: 24px;
  height: 24px;
  background-color: rgba(0, 0, 0, 0.6);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  cursor: pointer;
}

.images-preview {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}

.image-item {
  position: relative;
  width: calc((100% - 16px) / 3);
  aspect-ratio: 1;
  border-radius: 8px;
  overflow: hidden;
  background-color: #f4f4f5;
}

.preview-image {
  width: 100%;
  height: 100%;
}

.image-item .remove-btn {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 22px;
  height: 22px;
}

.file-type-badge {
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: #333;
  background-color: #f5f5f5;
  flex-shrink: 0;
}

.badge-pdf {
  background-color: #fff1f0;
  color: #f5222d;
}

.badge-doc {
  background-color: #f0f5ff;
  color: #2f54eb;
}

.badge-xls {
  background-color: #f6ffed;
  color: #52c41a;
}

.badge-ppt {
  background-color: #fff7e6;
  color: #fa8c16;
}

.badge-zip {
  background-color: #f9f0ff;
  color: #722ed1;
}

.badge-image {
  background-color: #fff7e6;
  color: #d48806;
}

.badge-other {
  background-color: #f5f5f5;
  color: #888;
}

.file-icon {
  font-size: 20px;
  color: #999;
  flex-shrink: 0;
}
</style>

