<script setup lang="ts">
/**
 * 文件职责：次卡编辑抽屉。
 */
import type { UploadChangeParam, UploadFile } from 'ant-design-vue';
import type { Dayjs } from 'dayjs';

import type { PunchCardEditorForm } from '../types';

import { ref } from 'vue';

import { IconifyIcon } from '@vben/icons';

import {
  Button,
  DatePicker,
  Drawer,
  Form,
  Input,
  InputNumber,
  message,
  Select,
  Switch,
  Upload,
} from 'ant-design-vue';
import dayjs from 'dayjs';

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

import {
  PUNCH_CARD_EXPIRE_STRATEGY_OPTIONS,
  PUNCH_CARD_NOTIFY_CHANNEL_OPTIONS,
  PUNCH_CARD_SCOPE_OPTIONS,
  PUNCH_CARD_USAGE_MODE_OPTIONS,
  PUNCH_CARD_VALIDITY_OPTIONS,
} from '../composables/punch-card-page/constants';

const props = defineProps<{
  canManage: boolean;
  categoryOptions: Array<{ label: string; value: string }>;
  form: PunchCardEditorForm;
  loading: boolean;
  open: boolean;
  scopeProductNames: Array<{ id: string; name: string }>;
  submitText: string;
  submitting: boolean;
  tagOptions: Array<{ label: string; value: string }>;
  title: string;
}>();

const emit = defineEmits<{
  (event: 'close'): void;
  (event: 'openScopeProductPicker'): void;
  (event: 'setAllowTransfer', value: boolean): void;
  (event: 'setCoverImageUrl', value: string): void;
  (event: 'setDailyLimit', value: null | number): void;
  (event: 'setDescription', value: string): void;
  (
    event: 'setExpireStrategy',
    value: PunchCardEditorForm['expireStrategy'],
  ): void;
  (event: 'setName', value: string): void;
  (event: 'setOriginalPrice', value: null | number): void;
  (event: 'setPerOrderLimit', value: null | number): void;
  (event: 'setPerUserPurchaseLimit', value: null | number): void;
  (event: 'setSalePrice', value: null | number): void;
  (event: 'setScopeCategoryIds', value: string[]): void;
  (event: 'setScopeProductIds', value: string[]): void;
  (event: 'setScopeTagIds', value: string[]): void;
  (
    event: 'setScopeType',
    value: PunchCardEditorForm['scope']['scopeType'],
  ): void;
  (event: 'setTotalTimes', value: null | number): void;
  (event: 'setUsageCapAmount', value: null | number): void;
  (event: 'setUsageMode', value: PunchCardEditorForm['usageMode']): void;
  (
    event: 'setValidDateRange',
    value: PunchCardEditorForm['validDateRange'],
  ): void;
  (event: 'setValidityDays', value: null | number): void;
  (event: 'setValidityType', value: PunchCardEditorForm['validityType']): void;
  (event: 'submit'): void;
  (event: 'toggleNotifyChannel', value: string): void;
}>();

const isUploading = ref(false);
type RangePickerValue = [Dayjs, Dayjs] | [string, string] | null;

function parseNullableNumber(value: null | number | string) {
  if (value === null || value === undefined || value === '') {
    return null;
  }
  const parsed = Number(value);
  return Number.isNaN(parsed) ? null : parsed;
}

function setScopeType(value: unknown) {
  if (
    value === 'all' ||
    value === 'category' ||
    value === 'tag' ||
    value === 'product'
  ) {
    emit('setScopeType', value);
  }
}

function setValidityType(value: unknown) {
  if (value === 'days' || value === 'range') {
    emit('setValidityType', value);
  }
}

function setUsageMode(value: unknown) {
  if (value === 'free' || value === 'cap') {
    emit('setUsageMode', value);
  }
}

function setExpireStrategy(value: unknown) {
  if (value === 'invalidate' || value === 'refund') {
    emit('setExpireStrategy', value);
  }
}

function setValidDateRange(value: RangePickerValue) {
  if (!value) {
    emit('setValidDateRange', null);
    return;
  }

  const [start, end] = value;
  if (dayjs.isDayjs(start) && dayjs.isDayjs(end)) {
    emit('setValidDateRange', [start, end]);
    return;
  }

  if (typeof start === 'string' && typeof end === 'string') {
    const parsedStart = dayjs(start);
    const parsedEnd = dayjs(end);
    if (parsedStart.isValid() && parsedEnd.isValid()) {
      emit('setValidDateRange', [parsedStart, parsedEnd]);
    }
  }
}

function setScopeCategoryIds(value: unknown) {
  if (Array.isArray(value)) {
    emit('setScopeCategoryIds', value.map(String));
  }
}

function setScopeTagIds(value: unknown) {
  if (Array.isArray(value)) {
    emit('setScopeTagIds', value.map(String));
  }
}

function removeScopeProduct(id: string) {
  emit(
    'setScopeProductIds',
    props.form.scope.productIds.filter((item) => item !== id),
  );
}

async function handleUploadChange(info: UploadChangeParam<UploadFile>) {
  const rawFile = info.file.originFileObj;
  if (!rawFile) {
    return;
  }

  isUploading.value = true;
  try {
    const result = await uploadTenantFileApi(rawFile, 'dish_image');
    if (result.url) {
      emit('setCoverImageUrl', result.url);
      message.success('上传成功');
    } else {
      message.error('上传失败');
    }
  } catch (error) {
    console.error(error);
    message.error('上传失败');
  } finally {
    isUploading.value = false;
  }
}
</script>

<template>
  <Drawer
    :open="open"
    :title="title"
    width="560"
    class="mpc-editor-drawer"
    @close="emit('close')"
  >
    <Form layout="vertical" class="mpc-editor-form">
      <Form.Item label="次卡名称" required>
        <Input
          :value="form.name"
          :disabled="!canManage || loading"
          placeholder="如：咖啡月卡、早餐周卡"
          :maxlength="64"
          @update:value="(value) => emit('setName', String(value ?? ''))"
        />
      </Form.Item>

      <Form.Item label="封面图片">
        <div class="mpc-cover-uploader">
          <img
            v-if="form.coverImageUrl"
            class="mpc-cover-preview"
            :src="form.coverImageUrl"
            alt="cover"
          />
          <Upload
            :show-upload-list="false"
            :before-upload="() => false"
            :disabled="!canManage || loading || isUploading"
            @change="handleUploadChange"
          >
            <Button :loading="isUploading" :disabled="!canManage || loading">
              <IconifyIcon icon="lucide:upload-cloud" />
              {{ form.coverImageUrl ? '重新上传' : '点击上传封面' }}
            </Button>
          </Upload>
        </div>
      </Form.Item>

      <div class="mpc-inline-row">
        <Form.Item label="售价" required>
          <InputNumber
            :value="form.salePrice ?? undefined"
            :min="0.01"
            :precision="2"
            :disabled="!canManage || loading"
            placeholder="如：99"
            @update:value="
              (value) => emit('setSalePrice', parseNullableNumber(value))
            "
          />
        </Form.Item>

        <Form.Item label="原价">
          <InputNumber
            :value="form.originalPrice ?? undefined"
            :min="0"
            :precision="2"
            :disabled="!canManage || loading"
            placeholder="如：150"
            @update:value="
              (value) => emit('setOriginalPrice', parseNullableNumber(value))
            "
          />
        </Form.Item>
      </div>

      <Form.Item label="总次数" required>
        <InputNumber
          :value="form.totalTimes ?? undefined"
          :min="1"
          :precision="0"
          :disabled="!canManage || loading"
          placeholder="如：30"
          @update:value="
            (value) => emit('setTotalTimes', parseNullableNumber(value))
          "
        />
        <div class="mpc-form-hint">购买后可使用的总次数</div>
      </Form.Item>

      <Form.Item label="有效期" required>
        <Select
          :value="form.validityType"
          :options="PUNCH_CARD_VALIDITY_OPTIONS"
          :disabled="!canManage || loading"
          @update:value="setValidityType"
        />
        <div v-if="form.validityType === 'days'" class="mpc-inline-fields">
          <span>购买后</span>
          <InputNumber
            :value="form.validityDays ?? undefined"
            :min="1"
            :precision="0"
            :disabled="!canManage || loading"
            placeholder="如：30"
            @update:value="
              (value) => emit('setValidityDays', parseNullableNumber(value))
            "
          />
          <span>天内有效</span>
        </div>

        <DatePicker.RangePicker
          v-else
          :value="form.validDateRange ?? undefined"
          :disabled="!canManage || loading"
          class="mpc-range-picker"
          @update:value="setValidDateRange"
        />
      </Form.Item>

      <div class="mpc-section-divider"></div>

      <Form.Item label="适用范围" required>
        <Select
          :value="form.scope.scopeType"
          :options="PUNCH_CARD_SCOPE_OPTIONS"
          :disabled="!canManage || loading"
          @update:value="setScopeType"
        />

        <template v-if="form.scope.scopeType === 'all'">
          <div class="mpc-form-hint">持卡可兑换店内任意商品</div>
        </template>

        <template v-else-if="form.scope.scopeType === 'category'">
          <Select
            mode="multiple"
            :value="form.scope.categoryIds"
            :options="categoryOptions"
            :disabled="!canManage || loading"
            placeholder="请选择商品分类"
            @update:value="setScopeCategoryIds"
          />
          <div class="mpc-form-hint">
            可多选，持卡可兑换所选分类下的任意商品
          </div>
        </template>

        <template v-else-if="form.scope.scopeType === 'tag'">
          <Select
            mode="multiple"
            :value="form.scope.tagIds"
            :options="tagOptions"
            :disabled="!canManage || loading"
            placeholder="请选择商品标签"
            @update:value="setScopeTagIds"
          />
          <div class="mpc-form-hint">可多选，持卡可兑换带有所选标签的商品</div>
        </template>

        <template v-else>
          <Button
            :disabled="!canManage || loading"
            @click="emit('openScopeProductPicker')"
          >
            <IconifyIcon icon="lucide:plus" />
            选择商品
          </Button>

          <div
            v-if="scopeProductNames.length > 0"
            class="mpc-selected-products"
          >
            <span
              v-for="item in scopeProductNames"
              :key="item.id"
              class="mpc-selected-product"
            >
              <span class="mpc-selected-product-name">{{ item.name }}</span>
              <button
                type="button"
                class="mpc-selected-product-remove"
                :disabled="!canManage || loading"
                @click="removeScopeProduct(item.id)"
              >
                <IconifyIcon icon="lucide:x" />
              </button>
            </span>
          </div>

          <div v-else class="mpc-form-hint">可多选，持卡仅可兑换指定商品</div>
        </template>
      </Form.Item>

      <Form.Item label="使用模式" required>
        <Select
          :value="form.usageMode"
          :options="PUNCH_CARD_USAGE_MODE_OPTIONS"
          :disabled="!canManage || loading"
          @update:value="setUsageMode"
        />

        <div v-if="form.usageMode === 'free'" class="mpc-form-hint">
          每次使用免费兑换一件适用范围内商品，不限原价
        </div>

        <div v-else class="mpc-inline-fields">
          <span>每次使用上限</span>
          <InputNumber
            :value="form.usageCapAmount ?? undefined"
            :min="0.01"
            :precision="2"
            :disabled="!canManage || loading"
            placeholder="如：20"
            @update:value="
              (value) => emit('setUsageCapAmount', parseNullableNumber(value))
            "
          />
          <span>元</span>
        </div>
      </Form.Item>

      <div class="mpc-section-divider"></div>

      <div class="mpc-inline-row">
        <Form.Item label="每日限用">
          <InputNumber
            :value="form.dailyLimit ?? undefined"
            :min="0"
            :precision="0"
            :disabled="!canManage || loading"
            placeholder="不限"
            @update:value="
              (value) => emit('setDailyLimit', parseNullableNumber(value))
            "
          />
        </Form.Item>

        <Form.Item label="每单限用">
          <InputNumber
            :value="form.perOrderLimit ?? undefined"
            :min="0"
            :precision="0"
            :disabled="!canManage || loading"
            placeholder="不限"
            @update:value="
              (value) => emit('setPerOrderLimit', parseNullableNumber(value))
            "
          />
        </Form.Item>

        <Form.Item label="每人限购">
          <InputNumber
            :value="form.perUserPurchaseLimit ?? undefined"
            :min="0"
            :precision="0"
            :disabled="!canManage || loading"
            placeholder="不限"
            @update:value="
              (value) =>
                emit('setPerUserPurchaseLimit', parseNullableNumber(value))
            "
          />
        </Form.Item>
      </div>

      <Form.Item label="允许转赠">
        <Switch
          :checked="form.allowTransfer"
          :disabled="!canManage || loading"
          @update:checked="(value) => emit('setAllowTransfer', Boolean(value))"
        />
      </Form.Item>

      <Form.Item label="过期策略">
        <Select
          :value="form.expireStrategy"
          :options="PUNCH_CARD_EXPIRE_STRATEGY_OPTIONS"
          :disabled="!canManage || loading"
          @update:value="setExpireStrategy"
        />
      </Form.Item>

      <Form.Item label="次卡描述">
        <Input.TextArea
          :value="form.description"
          :disabled="!canManage || loading"
          :maxlength="512"
          :rows="3"
          placeholder="请输入次卡说明，如使用规则、适用门店等"
          @update:value="(value) => emit('setDescription', String(value ?? ''))"
        />
      </Form.Item>

      <Form.Item label="购买通知">
        <div class="mpc-notify-pills">
          <button
            v-for="item in PUNCH_CARD_NOTIFY_CHANNEL_OPTIONS"
            :key="item.value"
            type="button"
            class="mpc-notify-pill"
            :class="{ checked: form.notifyChannels.includes(item.value) }"
            :disabled="!canManage || loading"
            @click="emit('toggleNotifyChannel', item.value)"
          >
            {{ item.label }}
          </button>
        </div>
        <div class="mpc-form-hint">顾客购买次卡后的通知方式</div>
      </Form.Item>
    </Form>

    <template #footer>
      <div class="mpc-drawer-footer">
        <Button @click="emit('close')">取消</Button>
        <Button
          type="primary"
          :loading="submitting"
          :disabled="!canManage || loading"
          @click="emit('submit')"
        >
          {{ submitText }}
        </Button>
      </div>
    </template>
  </Drawer>
</template>
