<script setup lang="ts">
import type { CategoryFormModel } from '../types';

/**
 * 文件职责：分类新增/编辑抽屉。
 */
import type { ProductCategoryChannel } from '#/api/product';

import { computed, onBeforeUnmount, ref } from 'vue';

import { VCropper } from '@vben/common-ui';
import { IconifyIcon } from '@vben/icons';

import {
  Button,
  Drawer,
  Form,
  FormItem,
  Input,
  InputNumber,
  message,
  Modal,
  Switch,
  Upload,
} from 'ant-design-vue';

import { uploadTenantFileApi } from '#/api/files';

import { CATEGORY_CHANNEL_META, CATEGORY_CHANNEL_ORDER } from '../types';

interface Props {
  form: CategoryFormModel;
  open: boolean;
  submitText: string;
  submitting: boolean;
  title: string;
}

interface Emits {
  (event: 'close'): void;
  (event: 'setDescription', value: string): void;
  (event: 'setIcon', value: string): void;
  (event: 'setName', value: string): void;
  (event: 'setSort', value: number): void;
  (event: 'submit'): void;
  (event: 'toggleChannel', channel: ProductCategoryChannel): void;
  (event: 'toggleStatus'): void;
}

const props = defineProps<Props>();
const emit = defineEmits<Emits>();

const cropOpen = ref(false);
const cropConfirming = ref(false);
const cropImageUrl = ref('');
const cropperRef = ref<InstanceType<typeof VCropper> | null>(null);

let cropObjectUrl = '';

const canPreviewIcon = computed(() => {
  const icon = props.form.icon.trim();
  if (!icon) return false;
  return (
    icon.startsWith('data:image/') ||
    icon.startsWith('http://') ||
    icon.startsWith('https://') ||
    icon.startsWith('/')
  );
});

function setName(value: string | undefined) {
  emit('setName', value ?? '');
}

function setDescription(value: string | undefined) {
  emit('setDescription', value ?? '');
}

function setSort(value: null | number | string) {
  let nextValue = 0;
  if (typeof value === 'number') {
    nextValue = value;
  } else if (typeof value === 'string') {
    nextValue = Number(value);
  }
  emit('setSort', nextValue);
}

function isAllowedIconFile(file: File) {
  if (file.type === 'image/png' || file.type === 'image/svg+xml') {
    return true;
  }
  const lowerName = file.name.toLowerCase();
  return lowerName.endsWith('.png') || lowerName.endsWith('.svg');
}

function resetCropState() {
  cropOpen.value = false;
  cropConfirming.value = false;
  cropImageUrl.value = '';
  cropperRef.value = null;

  if (!cropObjectUrl) {
    return;
  }
  URL.revokeObjectURL(cropObjectUrl);
  cropObjectUrl = '';
}

function openCropper(file: File) {
  if (cropObjectUrl) {
    URL.revokeObjectURL(cropObjectUrl);
  }
  cropObjectUrl = URL.createObjectURL(file);
  cropImageUrl.value = cropObjectUrl;
  cropOpen.value = true;
}

async function confirmCrop() {
  const cropper = cropperRef.value;
  if (!cropper) {
    message.error('裁剪组件未就绪，请重试');
    return;
  }

  cropConfirming.value = true;
  try {
    const cropResult = await cropper.getCropImage(
      'image/png',
      0.92,
      'base64',
      120,
      120,
    );

    if (
      typeof cropResult !== 'string' ||
      !cropResult.startsWith('data:image/')
    ) {
      message.error('裁剪失败，请调整裁剪框后重试');
      return;
    }

    const response = await fetch(cropResult);
    const blob = await response.blob();
    const file = new File([blob], `category-icon-${Date.now()}.png`, {
      type: 'image/png',
    });
    const uploadResult = await uploadTenantFileApi(file, 'dish_image');
    const uploadedUrl = String(uploadResult?.url ?? '').trim();

    if (!uploadedUrl) {
      message.error('上传失败，请重试');
      return;
    }

    emit('setIcon', uploadedUrl);
    resetCropState();
  } catch {
    message.error('裁剪或上传失败，请重试');
  } finally {
    cropConfirming.value = false;
  }
}

function cancelCrop() {
  resetCropState();
}

function beforeUpload(file: File) {
  if (!isAllowedIconFile(file)) {
    message.warning('仅支持 PNG/SVG 格式');
    return false;
  }

  if (file.size > 2 * 1024 * 1024) {
    message.warning('图标大小不能超过 2MB');
    return false;
  }

  openCropper(file);
  return false;
}

function handleDrawerOpenChange(open: boolean) {
  if (!open) {
    emit('close');
  }
}

function isChannelChecked(channel: ProductCategoryChannel) {
  return props.form.channels.includes(channel);
}

function getChannelButtonStyle(channel: ProductCategoryChannel) {
  if (isChannelChecked(channel)) {
    return {
      background: 'rgb(22 119 255 / 6%)',
      borderColor: '#1677ff',
      color: '#1677ff',
    };
  }
  return {
    background: '#fff',
    borderColor: '#e5e7eb',
    color: '#4b5563',
  };
}

function getChannelCheckStyle(channel: ProductCategoryChannel) {
  if (isChannelChecked(channel)) {
    return {
      background: '#1677ff',
      borderColor: '#1677ff',
    };
  }
  return {
    background: '#fff',
    borderColor: '#d1d5db',
  };
}

function getChannelCheckIconStyle(channel: ProductCategoryChannel) {
  return {
    color: isChannelChecked(channel) ? '#fff' : 'transparent',
  };
}

onBeforeUnmount(() => {
  if (cropObjectUrl) {
    URL.revokeObjectURL(cropObjectUrl);
    cropObjectUrl = '';
  }
});
</script>

<template>
  <Drawer
    class="pcat-editor-drawer-wrap"
    :open="props.open"
    :title="props.title"
    :width="480"
    :closable="false"
    destroy-on-close
    @close="emit('close')"
    @update:open="handleDrawerOpenChange"
  >
    <template #extra>
      <button type="button" class="pcat-drawer-close" @click="emit('close')">
        <IconifyIcon icon="lucide:x" />
      </button>
    </template>

    <Form layout="vertical" class="pcat-drawer-form">
      <FormItem label="分类名称" required>
        <Input
          :value="props.form.name"
          :maxlength="20"
          placeholder="请输入分类名称，如：热销推荐"
          @update:value="setName"
        />
      </FormItem>

      <FormItem label="分类描述">
        <Input.TextArea
          :value="props.form.description"
          :rows="2"
          :maxlength="100"
          placeholder="请输入分类描述，帮助顾客理解分类内容"
          @update:value="setDescription"
        />
      </FormItem>

      <FormItem label="分类图标">
        <Upload
          :show-upload-list="false"
          accept=".png,.svg,image/png,image/svg+xml"
          :before-upload="beforeUpload"
        >
          <div class="pcat-icon-upload">
            <img
              v-if="canPreviewIcon"
              :src="props.form.icon"
              class="pcat-icon-preview"
              alt="分类图标"
            />
            <template v-else>
              <span class="pcat-icon-plus">+</span>
              <span class="pcat-icon-upload-text">上传图标</span>
            </template>
          </div>
        </Upload>
        <div class="pcat-hint">建议尺寸 120x120px，支持 PNG/SVG</div>
      </FormItem>

      <FormItem label="销售渠道" required>
        <div class="pcat-hint mb-8">选择该分类在哪些渠道展示，至少选择一个</div>
        <div class="pcat-drawer-channels">
          <button
            v-for="channel in CATEGORY_CHANNEL_ORDER"
            :key="`drawer-channel-${channel}`"
            type="button"
            class="pcat-drawer-ch"
            :style="getChannelButtonStyle(channel)"
            @click="emit('toggleChannel', channel)"
          >
            <span class="pcat-ch-check" :style="getChannelCheckStyle(channel)">
              <IconifyIcon
                icon="lucide:check"
                class="pcat-ch-check-icon"
                :style="getChannelCheckIconStyle(channel)"
              />
            </span>
            <IconifyIcon
              class="pcat-drawer-ch-icon"
              :icon="CATEGORY_CHANNEL_META[channel].icon"
            />
            {{ CATEGORY_CHANNEL_META[channel].label }}
          </button>
        </div>
      </FormItem>

      <FormItem label="排序">
        <InputNumber
          :value="props.form.sort"
          class="pcat-sort-input"
          :min="1"
          :controls="false"
          placeholder="数字越小越靠前，如：1"
          @update:value="setSort"
        />
      </FormItem>

      <FormItem label="启用状态">
        <div class="pcat-toggle-row">
          <Switch
            :checked="props.form.status === 'enabled'"
            @change="emit('toggleStatus')"
          />
          <span class="pcat-toggle-label">
            {{ props.form.status === 'enabled' ? '启用' : '停用' }}
          </span>
        </div>
      </FormItem>
    </Form>

    <template #footer>
      <div class="pcat-drawer-ft">
        <Button @click="emit('close')">取消</Button>
        <Button
          type="primary"
          :loading="props.submitting"
          @click="emit('submit')"
        >
          {{ props.submitting ? '保存中...' : props.submitText }}
        </Button>
      </div>
    </template>
  </Drawer>

  <Modal
    :open="cropOpen"
    title="裁剪分类图标"
    :width="560"
    :mask-closable="false"
    :keyboard="false"
    :confirm-loading="cropConfirming"
    destroy-on-close
    ok-text="确认"
    cancel-text="取消"
    class="pcat-crop-modal"
    @ok="confirmCrop"
    @cancel="cancelCrop"
  >
    <div class="pcat-cropper-wrap">
      <VCropper ref="cropperRef" :img="cropImageUrl" aspect-ratio="1:1" />
    </div>
    <div class="pcat-crop-hint">
      拖拽裁剪框选择展示区域，确认后自动保存为 120x120 PNG。
    </div>
  </Modal>
</template>
