<script setup lang="ts">
import type { VbenFormProps } from '#/adapter/form';
import { useVbenForm } from '#/adapter/form';
import {
  createExperimentApi,
  getExperimentVariantsApi,
  getExperimentWhitelistApi,
  updateExperimentApi,
} from '#/api/core/experiment';
import type { ExperimentApi } from '#/api/core/experiment';
import { useVbenModal } from '@vben/common-ui';
import { Alert, Button, Card, Input, InputNumber, Select, Space, message } from 'ant-design-vue';
import { computed, ref } from 'vue';

interface ModalData {
  mode: 'create' | 'edit';
  record?: ExperimentApi.ExperimentItem;
}

interface VariantDraft {
  clientKey: string;
  description: string;
  id?: number;
  name: string;
  paramsText: string;
  weight: number;
}

interface WhitelistDraft {
  clientKey: string;
  userId: string;
  variantClientKey: string;
}

const statusOptions = [
  { label: '草稿', value: 0 },
  { label: '运行中', value: 1 },
  { label: '已暂停', value: 2 },
  { label: '已结束', value: 3 },
];

let draftSeed = 0;

function createDraftKey(prefix: string) {
  draftSeed += 1;
  return `${prefix}-${draftSeed}`;
}

function createVariantDraft(
  value?: Partial<ExperimentApi.VariantItem> & { clientKey?: string },
): VariantDraft {
  return {
    clientKey: value?.clientKey || createDraftKey('variant'),
    description: value?.description || '',
    id: value?.id,
    name: value?.name || '',
    paramsText: value?.params ? JSON.stringify(value.params, null, 2) : '{}',
    weight: value?.weight || 1,
  };
}

function createWhitelistDraft(value?: {
  clientKey?: string;
  userId?: string;
  variantClientKey?: string;
}) {
  return {
    clientKey: value?.clientKey || createDraftKey('whitelist'),
    userId: value?.userId || '',
    variantClientKey: value?.variantClientKey || '',
  };
}

const variants = ref<VariantDraft[]>([]);
const whitelist = ref<WhitelistDraft[]>([]);

const variantOptions = computed(() =>
  variants.value.map((item, index) => ({
    label: item.name || `变体${index + 1}`,
    value: item.clientKey,
  })),
);

function resetChildren() {
  variants.value = [
    createVariantDraft({ name: 'control' }),
    createVariantDraft({ name: 'treatment' }),
  ];
  whitelist.value = [];
}

function addVariant() {
  variants.value.push(createVariantDraft());
}

function removeVariant(clientKey: string) {
  variants.value = variants.value.filter((item) => item.clientKey !== clientKey);
  whitelist.value = whitelist.value.map((item) => {
    if (item.variantClientKey === clientKey) {
      return {
        ...item,
        variantClientKey: '',
      };
    }
    return item;
  });
}

function addWhitelist() {
  whitelist.value.push(createWhitelistDraft());
}

function removeWhitelist(clientKey: string) {
  whitelist.value = whitelist.value.filter((item) => item.clientKey !== clientKey);
}

function buildBasePayload(values: Record<string, any>): ExperimentApi.UpdateParams {
  return {
    description: values.description || '',
    end_time: values.end_time || null,
    name: values.name,
    start_time: values.start_time || null,
    status: values.status,
  };
}

function buildExperimentWhitelistPayload() {
  const variantPayloads = parseVariantPayloads();
  const variantNameByClientKey = new Map(
    variantPayloads.map((item) => [item.clientKey, item.payload.name]),
  );
  const userSet = new Set<string>();

  return whitelist.value.map((item, index) => {
    const userId = item.userId.trim();
    if (!userId) {
      throw new Error(`第${index + 1}条白名单用户不能为空`);
    }
    if (userSet.has(userId)) {
      throw new Error(`白名单用户“${userId}”重复`);
    }
    userSet.add(userId);

    if (!item.variantClientKey || !variantNameByClientKey.has(item.variantClientKey)) {
      throw new Error(`第${index + 1}条白名单绑定的变体无效`);
    }

    return {
      user_id: userId,
      variant_name: variantNameByClientKey.get(item.variantClientKey) as string,
    };
  });
}

function buildCreatePayload(values: Record<string, any>): ExperimentApi.CreateParams {
  const payload = buildBasePayload(values);
  const variantPayloads = parseVariantPayloads();
  const whitelistPayloads = buildExperimentWhitelistPayload();

  return {
    description: String(payload.description || ''),
    end_time: payload.end_time || null,
    name: String(payload.name || ''),
    start_time: payload.start_time || null,
    status: payload.status,
    variants: variantPayloads.map((item) => item.payload),
    whitelist: whitelistPayloads,
  };
}

function buildUpdatePayload(values: Record<string, any>): ExperimentApi.UpdateParams {
  const payload = buildBasePayload(values);
  const variantPayloads = parseVariantPayloads();

  return {
    ...payload,
    variants: variantPayloads.map((item) => ({
      ...item.payload,
      id: item.id,
    })),
    whitelist: buildExperimentWhitelistPayload(),
  };
}

function parseVariantPayloads() {
  if (variants.value.length === 0) {
    throw new Error('请至少配置一个变体');
  }

  const nameSet = new Set<string>();

  return variants.value.map((item, index) => {
    const name = item.name.trim();
    if (!name) {
      throw new Error(`第${index + 1}个变体名称不能为空`);
    }
    if (nameSet.has(name)) {
      throw new Error(`变体名称“${name}”重复`);
    }
    nameSet.add(name);

    let params: any = null;
    if (item.paramsText.trim()) {
      try {
        params = JSON.parse(item.paramsText);
      } catch {
        throw new Error(`第${index + 1}个变体参数不是合法 JSON`);
      }
    }

    return {
      clientKey: item.clientKey,
      id: item.id,
      payload: {
        description: item.description.trim(),
        name,
        params,
        weight: item.weight > 0 ? item.weight : 1,
      },
    };
  });
}

async function loadChildren(experimentId: number) {
  const [variantList, whitelistList] = await Promise.all([
    getExperimentVariantsApi(experimentId),
    getExperimentWhitelistApi(experimentId),
  ]);

  const safeVariantList = Array.isArray(variantList) ? variantList : [];
  const safeWhitelistList = Array.isArray(whitelistList) ? whitelistList : [];

  const variantDrafts = safeVariantList.map((item) =>
    createVariantDraft({
      ...item,
      clientKey: `variant-${item.id}`,
    }),
  );
  const variantClientKeyById = new Map(
    variantDrafts
      .filter((item) => item.id)
      .map((item) => [item.id as number, item.clientKey]),
  );

  variants.value = variantDrafts.length > 0 ? variantDrafts : [createVariantDraft()];
  whitelist.value = safeWhitelistList.map((item) =>
    createWhitelistDraft({
      clientKey: `whitelist-${item.id}`,
      userId: item.user_id,
      variantClientKey: variantClientKeyById.get(item.variant_id) || '',
    }),
  );
}

const formOptions: VbenFormProps = {
  commonConfig: {
    componentProps: {
      class: 'w-full',
    },
  },
  layout: 'horizontal',
  schema: [
    {
      component: 'Input',
      fieldName: 'name',
      label: '实验名称',
      rules: 'required',
    },
    {
      component: 'Textarea',
      componentProps: {
        rows: 4,
      },
      fieldName: 'description',
      label: '实验描述',
    },
    {
      component: 'Select',
      componentProps: {
        options: statusOptions,
      },
      defaultValue: 0,
      fieldName: 'status',
      label: '状态',
    },
    {
      component: 'DatePicker',
      componentProps: {
        showTime: true,
        valueFormat: 'YYYY-MM-DD HH:mm:ss',
      },
      fieldName: 'start_time',
      label: '开始时间',
    },
    {
      component: 'DatePicker',
      componentProps: {
        showTime: true,
        valueFormat: 'YYYY-MM-DD HH:mm:ss',
      },
      fieldName: 'end_time',
      label: '结束时间',
    },
  ],
  showDefaultActions: false,
};

const [Form, FormApi] = useVbenForm(formOptions);

const [Modal, modalApi] = useVbenModal({
  confirmText: '提交',
  onOpenChange: async (isOpen) => {
    if (!isOpen) {
      await FormApi.resetForm();
      resetChildren();
      return;
    }

    const data = (modalApi.getData() ?? { mode: 'create' }) as ModalData;

    if (data.mode === 'edit' && data.record) {
      await FormApi.setValues({
        description: data.record.description,
        end_time: data.record.end_time ?? undefined,
        name: data.record.name,
        start_time: data.record.start_time ?? undefined,
        status: data.record.status,
      });
      await loadChildren(data.record.id);
      return;
    }

    await FormApi.setValues({
      description: '',
      end_time: undefined,
      name: '',
      start_time: undefined,
      status: 0,
    });
    resetChildren();
  },
  onConfirm: async () => {
    const data = (modalApi.getData() ?? { mode: 'create' }) as ModalData;
    const values = await FormApi.getValues();

    if (data.mode === 'edit' && data.record) {
      await updateExperimentApi(data.record.id, buildUpdatePayload(values));
      message.success('实验更新成功');
    } else {
      await createExperimentApi(buildCreatePayload(values));
      message.success('实验创建成功');
    }

    modalApi.close();
  },
});

defineOptions({
  name: 'ExperimentFormModal',
});
</script>

<template>
  <Modal :title="modalApi.getData()?.mode === 'edit' ? '编辑实验' : '新增实验'" :width="980">
    <div class="space-y-4">
      <Form />

      <Alert
        message="保存实验时会同步提交变体与白名单配置，白名单用户会强制命中对应变体。"
        type="info"
      />

      <Card title="变体配置" size="small">
        <template #extra>
          <Button type="link" @click="addVariant">新增变体</Button>
        </template>
        <div class="space-y-3">
          <div
            v-for="(item, index) in variants"
            :key="item.clientKey"
            class="rounded border border-solid border-gray-200 p-3"
          >
            <div class="mb-3 flex items-center justify-between">
              <div class="font-medium">变体 {{ index + 1 }}</div>
              <Button danger type="link" @click="removeVariant(item.clientKey)">删除</Button>
            </div>
            <div class="grid grid-cols-1 gap-3 md:grid-cols-2">
              <Input v-model:value="item.name" placeholder="变体名称，如 control" />
              <InputNumber v-model:value="item.weight" :min="1" class="w-full" placeholder="权重" />
            </div>
            <Input.TextArea
              v-model:value="item.description"
              :rows="2"
              class="mt-3"
              placeholder="变体描述"
            />
            <Input.TextArea
              v-model:value="item.paramsText"
              :rows="6"
              class="mt-3"
              placeholder='变体参数 JSON，例如 {"color":"red"}'
            />
          </div>
        </div>
      </Card>

      <Card title="白名单配置" size="small">
        <template #extra>
          <Button type="link" @click="addWhitelist">新增白名单</Button>
        </template>
        <div v-if="whitelist.length === 0" class="py-4 text-center text-gray-400">
          暂无白名单配置
        </div>
        <div v-else class="space-y-3">
          <div
            v-for="(item, index) in whitelist"
            :key="item.clientKey"
            class="rounded border border-solid border-gray-200 p-3"
          >
            <Space class="w-full" direction="vertical" size="middle">
              <Input v-model:value="item.userId" placeholder="用户标识 user_id" />
              <Select
                v-model:value="item.variantClientKey"
                :options="variantOptions"
                placeholder="选择命中的变体"
              />
              <div class="text-right">
                <Button danger type="link" @click="removeWhitelist(item.clientKey)">
                  删除白名单 {{ index + 1 }}
                </Button>
              </div>
            </Space>
          </div>
        </div>
      </Card>
    </div>
  </Modal>
</template>