<template>
  <DynamicForm
    ref="formRef"
    :model="currentForm"
    :options="mergedFormOptions"
  />
  
  <FlexCol>
    <Divider />
    <H3>自查项目选择</H3>
    <Height :height="30" />
    <FlexCol gap="gap.md">
      <FlexCol v-for="(item, index) in checkItemList" :key="item.id" gap="gap.md">
        <FlexRow justify="space-between" align="center">
          <Text fontConfig="subTitleText" :text="`${index + 1}. ${item.name}`" />
          <Tag :text="getCheckModeText(item.checkType)" />
        </FlexRow>
        <FlexCol v-if="item.checkType == 3" gap="gap.sm">
          <FlexRow v-for="child in item.children" :key="child.id" justify="space-between">
            <CheckBox
              :disabled="readonly"
              :text="`${child.name} (${child.points}分)`"
              :modelValue="hasCheckedItem(child.id)" 
              @update:modelValue="setCheckedItem(item as CheckItemInfo, child as CheckItemInfo, $event)" 
            />
            <Stepper 
              v-if="hasCheckedItem(child.id)"
              :disabled="readonly"
              :min="0"
              :max="20"
              :step="1"
              :modelValue="getCheckedItemCount(child.id) ?? 0" 
              addonAfter="次"
              @update:modelValue="setCheckedItem(item as CheckItemInfo, child as CheckItemInfo, $event)" 
            />
            <view v-else></view>
          </FlexRow>
        </FlexCol>
        <FlexCol v-else gap="gap.sm">
          <CheckBox 
            v-for="child in item.children" :key="child.id"
            :disabled="readonly"
            :text="`${child.name} (${child.points}分)`"
            :modelValue="hasCheckedItem(child.id)" 
            @update:modelValue="setCheckedItem(item as CheckItemInfo, child as CheckItemInfo, $event)" 
          />
        </FlexCol>
        <FlexCol gap="gap.sm" border="1px solid #e0e0e0" radius="radius.md" padding="space.md">
          <Text
            fontConfig="subText"
            color="text.second"
            :text="readonly ? '佐证资料' : '佐证材料上传，支持图片、视频、音频、文档（word、pdf、excel、ppt）等格式'"
          />
          <Text
            v-if="!currentForm.id"
            fontConfig="subText"
            color="text.second"
            text="请先保存评估表后再上传佐证资料"
          />
          <Uploader
            v-show="currentForm.id"
            :ref="(el) => bindUploaderRef(item.id, el)"
            :upload="getAnnexUpload(item.id)"
            :onDeleteClick="(file) => handleAnnexRemove(item.id, file)"
            :max-upload-count="100"
            :max-file-size="20 * 1024 * 1024"
            :group-type="true"
            chooseType="file"
            list-type="list"
            :itemExtraButtons="readonly ? [] : [{ icon: 'edit', onClick: (item2) => editAnnexDesc(item.id, item2) }]"
            :readonly="readonly"
          />
        </FlexCol>
      </FlexCol>
    </FlexCol>
  </FlexCol>

  <FlexCol>
    <Divider />
    <FlexRow justify="space-between" align="center">
      <H3>自评总分</H3>
      <Text fontConfig="subTitleText" color="text.primary" :text="`${totalPoints} 分`" />
    </FlexRow>
  </FlexCol>

  <DynamicForm
    ref="formRef2"
    :model="currentForm"
    :options="mergedFormOptionsEnd"
  />
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import DynamicForm from '@/components/dynamic/DynamicForm.vue';
import FlexCol from '@/components/layout/FlexCol.vue';
import H3 from '@/components/typography/H3.vue';
import Text from '@/components/basic/Text.vue';
import FlexRow from '@/components/layout/FlexRow.vue';
import CheckBox from '@/components/form/CheckBox.vue';
import Stepper from '@/components/form/Stepper.vue';
import Uploader, { type UploaderInstance } from '@/components/form/Uploader.vue';
import AssessmentContentApi, { getCheckAnnexType, SelfAssessmentCheckItemAnswer, type CheckItemInfo, type SelfAssessmentDetail } from '@/api/collect/AssessmentContent';
import AgentWorkApi from '@/api/agent/AgentWorks';
import type { IDynamicFormOptions, IDynamicFormRef } from '@/components/dynamic';
import { ArrayUtils } from '@imengyu/imengyu-utils';
import Tag from '@/components/display/Tag.vue';
import Divider from '@/components/display/Divider.vue';
import Height from '@/components/layout/space/Height.vue';
import { useAliOssUploadCo } from '@/common/components/upload/AliOssUploadCo';
import { getMimeType } from '@/common/components/upload/mimes';
import { stringUrlToUploaderItem, type UploaderAction, type UploaderItem } from '@/components/form/Uploader';

const props = withDefaults(defineProps<{
  currentForm: SelfAssessmentDetail;
  formOptions: IDynamicFormOptions;
  formOptionsEnd: IDynamicFormOptions;
  checkItemList: CheckItemInfo[];
  currentFormCheckItems: SelfAssessmentCheckItemAnswer[];
  /** 管理员只读查看 / 审核页 */
  readonly?: boolean;
}>(), {
  readonly: false,
});

const formRef = ref<IDynamicFormRef | null>(null);
const formRef2 = ref<IDynamicFormRef | null>(null);
const uploaderRefMap = new Map<number, UploaderInstance | null>();
const uploadCoMap = new Map<number, (action: UploaderAction) => (() => void)>();

const mergedFormOptions = computed<IDynamicFormOptions>(() => ({
  ...props.formOptions,
  formAdditionaProps: {
    ...props.formOptions.formAdditionaProps,
    disabled: props.readonly,
  },
}));
const mergedFormOptionsEnd = computed<IDynamicFormOptions>(() => ({
  ...props.formOptionsEnd,
  formAdditionaProps: {
    ...props.formOptionsEnd.formAdditionaProps,
    disabled: props.readonly,
  },
}));

function getCheckModeText(checkMode: number) {
  switch (checkMode) {
    case 1:
      return '单选';
    case 2:
      return '多选';
    case 3:
      return '可多次';
  }
}
function hasCheckedItem(id: number) {
  return props.currentFormCheckItems.some(item => item.id === id);
}
function getCheckedItemCount(id: number) {
  return props.currentFormCheckItems.find(item => item.id === id)?.count;
}
function setCheckedItem(checkItem: CheckItemInfo, childItem: CheckItemInfo, count: number|boolean) {
  if (props.readonly)
    return;
  if (typeof count === 'boolean') {
    count = count ? 1 : 0;
  }
  let item = props.currentFormCheckItems.find(item => item.id === childItem.id);
  if (!item) {
    item = new SelfAssessmentCheckItemAnswer();
    props.currentFormCheckItems.push(item);
  }
  if (item.count === count)
    return;
  item.id = childItem.id;
  item.points = childItem.points;
  item.count = count;
  switch (checkItem.checkType) {
    case 1: {
      /** 单选,清除其他选项 */
      const allChildren = checkItem.children.map(child => child.id);
      props.currentFormCheckItems.forEach(item => {
        if (allChildren.includes(item.id) && item.id !== childItem.id)
          item.count = 0;
      });
      for (let i = props.currentFormCheckItems.length - 1; i >= 0; i--) {
        if (props.currentFormCheckItems[i].count === 0)
          props.currentFormCheckItems.splice(i, 1);
      }
      break;
    }
  }
  if (item.count === 0)
    ArrayUtils.remove(props.currentFormCheckItems, item);
}


function formatAnnexDisplayName(desc: string | null | undefined, name: string) {
  const descText = (desc ?? '').trim();
  if (!descText)
    return name;
  return `${descText}（${name}）`;
}

function buildAnnexDescInputDoc() {
  const content = props.currentForm.content;
  if (!content)
    return '';
  const lines: string[] = [];
  for (let i = 0; i <= 6; i++) {
    const value = String(content[`item${i}`] ?? '').trim();
    if (!value)
      continue;
    lines.push(`第${i + 1}项：${value}`);
  }
  return lines.join('\n');
}

type AnnexUploaderItem = UploaderItem & {
  annexMeta?: {
    id: number;
    rawName: string;
    desc: string;
    url: string;
    type: number;
    mimetype?: string|null;
    attachId?: number|null;
    fileSize?: number|null;
  };
};

function createAnnexUploaderItem(item: {
  id: number;
  name: string;
  desc?: string|null;
  url: string;
  type: number;
  mimetype?: string|null;
  attachId?: number|null;
  fileSize?: number|null;
}) {
  const displayName = formatAnnexDisplayName(item.desc, item.name);
  const uploaderItem = stringUrlToUploaderItem(item.url, displayName) as AnnexUploaderItem;
  uploaderItem.annexMeta = {
    id: item.id,
    rawName: item.name,
    desc: item.desc ?? '',
    url: item.url,
    type: item.type,
    mimetype: item.mimetype,
    attachId: item.attachId,
    fileSize: item.fileSize,
  };
  return uploaderItem;
}

function promptAnnexDesc(initialDesc: string, title: string) {
  return new Promise<string|null>((resolve) => {
    uni.showModal({
      title,
      editable: true,
      placeholderText: '请输入佐证资料说明（可选）',
      content: initialDesc,
      success: (res) => {
        if (!res.confirm) {
          resolve(null);
          return;
        }
        resolve((res.content ?? '').trim());
      },
      fail: () => resolve(null),
    });
  });
}

async function editAnnexDesc(itemId: number, item: UploaderItem, isAfterUpload = false) {
  const formId = props.currentForm.id;
  if (!formId)
    return;
  const annexItem = item as AnnexUploaderItem;
  const meta = annexItem.annexMeta;
  if (!meta?.id) {
    uni.showToast({ title: '附件信息不完整，无法编辑说明', icon: 'none' });
    return;
  }
  const nextDesc = await promptAnnexDesc(
    meta.desc ?? '',
    isAfterUpload ? '上传成功，请补充附件说明' : '编辑附件说明',
  );
  if (nextDesc === null)
    return;
  item.name = nextDesc;
  await AssessmentContentApi.saveAnnex({
    id: meta.id,
    name: meta.rawName,
    formId,
    itemId,
    url: meta.url,
    type: meta.type,
    desc: nextDesc,
    mimetype: meta.mimetype ?? undefined,
    attachId: meta.attachId ?? undefined,
    fileSize: meta.fileSize ?? undefined,
  });
  await loadAnnexListByItem(itemId);
}

function bindUploaderRef(itemId: number, el: unknown) {
  uploaderRefMap.set(itemId, (el as UploaderInstance | null) || null);
  if (el)
    loadAnnexListByItem(itemId);
}

function handleAnnexRemove(itemId: number, item: UploaderItem): Promise<void> {
  const annexItem = item as AnnexUploaderItem;
  const meta = annexItem.annexMeta;
  if (!meta?.id || item.state !== 'success')
    return Promise.resolve();
  return new Promise((resolve, reject) => {
    uni.showModal({
      title: '确认删除',
      content: '确定要删除该佐证材料吗？',
      confirmText: '删除',
      confirmColor: '#ff4d4f',
      success: async (res) => {
        if (!res.confirm) {
          reject(new Error('cancel'));
          return;
        }
        try {
          await AssessmentContentApi.delAnnex(meta.id);
          await loadAnnexListByItem(itemId);
          uni.showToast({ title: '删除成功', icon: 'success' });
          resolve();
        } catch (err) {
          uni.showToast({
            title: err instanceof Error ? err.message : '删除失败',
            icon: 'none',
          });
          reject(err);
        }
      },
      fail: () => reject(new Error('cancel')),
    });
  });
}

function getAnnexUpload(itemId: number) {
  const cached = uploadCoMap.get(itemId);
  if (cached)
    return cached;
  const uploadCo = useAliOssUploadCo('assessment/annex', async (res, item) => {
    const formId = props.currentForm.id;
    if (!formId)
      return;
    const mimetype = getMimeType(item.filePath);
    const inputDoc = buildAnnexDescInputDoc();
    const desc = /*inputDoc
      ? await AgentWorkApi.generateFileDescByInputDoc(inputDoc, item.name)
      :*/ '';
    await AssessmentContentApi.saveAnnex({
      name: item.name,
      formId,
      itemId,
      desc,
      url: res,
      type: getCheckAnnexType(mimetype),
      mimetype,
      fileSize: item.size
        ? Math.max(1, Math.ceil(item.size / 1024))
        : undefined,
    });
    await loadAnnexListByItem(itemId);
    const uploaded = uploaderRefMap.get(itemId)?.getList().find((listItem) => {
      const meta = (listItem as AnnexUploaderItem).annexMeta;
      return meta?.url === res;
    });
    if (uploaded)
      await editAnnexDesc(itemId, uploaded, true);
  });
  uploadCoMap.set(itemId, uploadCo);
  return uploadCo;
}

async function loadAnnexListByItem(itemId: number) {
  const formId = props.currentForm.id;
  const uploaderRef = uploaderRefMap.get(itemId);
  if (!uploaderRef)
    return;
  if (!formId) {
    uploaderRef.setList([]);
    return;
  }
  const annexList = await AssessmentContentApi.getAnnexList(formId, itemId);
  uploaderRef.setList(annexList.data.map((item) => createAnnexUploaderItem(item)));
}

async function reloadAllAnnexList() {
  const itemIds = props.checkItemList.map((item) => item.id);
  await Promise.all(itemIds.map(loadAnnexListByItem));
}

const checkItemMap = computed(() => {
  const m = new Map<number, CheckItemInfo & { parent?: CheckItemInfo }>();
  for (const n of props.checkItemList) {
    m.set(n.id, n);
    if (n.children?.length) {
      for (const child of n.children) {
        (child as any).parent = n;
        m.set(child.id, child as CheckItemInfo & { parent?: CheckItemInfo });
      }
    }
  }
  return m;
});

const totalPoints = computed(() => {
  const groupMap = new Map<number, number>();
  for (const item of props.currentFormCheckItems) {
    const checkItem = checkItemMap.value.get(item.id);
    if (!checkItem || !checkItem.parent)
      continue;
    const parentId = checkItem.parent.id;
    const score = (item.points ?? 0) * (item.count ?? 1);
    groupMap.set(parentId, (groupMap.get(parentId) ?? 0) + score);
  }
  let total = 0;
  for (const [parentId, groupScore] of groupMap) {
    const parent = checkItemMap.value.get(parentId);
    const maxPoints = parent?.points ?? Infinity;
    total += Math.min(groupScore, maxPoints);
  }
  total -= (props.currentForm.deductPoints ?? 0);
  return total;
});

async function validate() {
  if (props.readonly)
    return;
  await formRef.value?.validate();
  await formRef2.value?.validate();
}

watch(
  () => [props.currentForm.id, props.checkItemList.map((item) => item.id).join(',')],
  () => {
    setTimeout(() => {
      reloadAllAnnexList();
    }, 2000);
  },
  { immediate: true },
);

defineExpose({ validate });
</script>