<script setup lang="ts">
import { computed, nextTick, onMounted, reactive, ref } from "vue";
import type { CSSProperties, Ref } from "vue";
import { ElMessage, FormInstance, FormRules } from "element-plus";
import type {
  UploadFile,
  UploadRequestOptions,
  UploadUserFile
} from "element-plus";
import Plus from "@iconify-icons/ep/plus";
import {
  AddCollaborationRecordCommand,
  CollaborationFileCommand,
  CollaborationFileType,
  CollaborationRecordPageResponse,
  UpdateCollaborationRecordCommand,
  addCollaborationRecordApi,
  getCollaborationRecordInfoApi,
  updateCollaborationRecordApi,
  uploadCollaborationFileApi
} from "@/api/collaboration/record";

interface Props {
  type: "add" | "update";
  row?: CollaborationRecordPageResponse;
  optionMap: Record<string, string[]>;
}

const props = defineProps<Props>();
type TabName = "basic" | "tasks" | "expenditures" | "settlements";

const tabNames: TabName[] = ["basic", "tasks", "expenditures", "settlements"];

const defaultFormData = (): AddCollaborationRecordCommand &
  Partial<UpdateCollaborationRecordCommand> => ({
  recordId: 0,
  brand: "",
  goods: "",
  cooperationPlatform: "小红书",
  imageReturnNum: 1,
  retainedMethod: "寄拍",
  cooperatedMethod: "水下",
  purchaseMethod: "拍单",
  purchasePrice: undefined,
  purchaseDate: "",
  purchasePlatform: "",
  deadline: "",
  remuneration: undefined,
  completeDate: "",
  requirements: "",
  remark: "",
  tasks: [{ releaseDate: "" }],
  expenditures: [],
  settlements: [],
  files: []
});

const formData = reactive(defaultFormData());
const formRef = ref<FormInstance>();
const activeTab = ref<TabName>("basic");
const basicPaneRef = ref<HTMLElement>();
const tasksPaneRef = ref<HTMLElement>();
const expendituresPaneRef = ref<HTMLElement>();
const settlementsPaneRef = ref<HTMLElement>();
const isMeasuringTabHeight = ref(false);
const tabContentHeight = ref(0);
const previewImageUrl = ref("");
const isImagePreviewVisible = ref(false);

const rules: FormRules = {
  brand: [{ required: true, message: "品牌不能为空" }],
  goods: [{ required: true, message: "物品不能为空" }],
  cooperationPlatform: [{ required: true, message: "合作平台不能为空" }],
  imageReturnNum: [{ required: true, message: "返图数量不能为空" }],
  deadline: [{ required: true, message: "预完成日期不能为空" }]
};

const goodsImages = computed(() =>
  formData.files.filter(item => item.fileType === "GOODS_IMAGE")
);
const attachments = computed(() =>
  formData.files.filter(item => item.fileType === "ATTACHMENT")
);
const goodsImageUploadFiles = computed<UploadUserFile[]>(() =>
  goodsImages.value.map(file => ({
    name: getFileName(file),
    url: getFileUrl(file)
  }))
);
const attachmentUploadFiles = computed<UploadUserFile[]>(() =>
  attachments.value.map(file => ({
    name: getFileName(file),
    url: getFileUrl(file)
  }))
);
const recordTabsStyle = computed<CSSProperties>(() => {
  if (!tabContentHeight.value) return {};
  return {
    "--record-tab-content-height": `${tabContentHeight.value}px`
  } as CSSProperties;
});

async function handleOpened() {
  resetFormData();
  if (props.type === "update" && props.row?.recordId) {
    await loadDetail(props.row.recordId);
  }
  await setFixedTabContentHeight();
}

function resetFormData() {
  Object.assign(formData, defaultFormData());
  formRef.value?.clearValidate();
}

async function loadDetail(recordId: number) {
  const { data } = await getCollaborationRecordInfoApi(recordId);
  Object.assign(formData, {
    ...defaultFormData(),
    ...data,
    tasks: data.tasks.length ? data.tasks : [{ releaseDate: "" }],
    expenditures: data.expenditures,
    settlements: data.settlements,
    files: data.files
  });
}

function addTask() {
  formData.tasks.push({ releaseDate: "" });
}

function removeTask(index: number) {
  formData.tasks.splice(index, 1);
}

function addExpenditure() {
  formData.expenditures.push({
    spendDate: "",
    amount: undefined,
    purpose: ""
  });
}

function removeExpenditure(index: number) {
  formData.expenditures.splice(index, 1);
}

function addSettlement() {
  formData.settlements.push({
    settleDate: "",
    method: "",
    income: undefined,
    purpose: ""
  });
}

function removeSettlement(index: number) {
  formData.settlements.splice(index, 1);
}

async function handleUpload(
  option: UploadRequestOptions,
  fileType: CollaborationFileType
) {
  const data = new FormData();
  data.append("file", option.file);
  const response = await uploadCollaborationFileApi(data);
  formData.files.push(toFileCommand(response.data, fileType));
  option.onSuccess(response.data);
}

function toFileCommand(file, fileType: CollaborationFileType) {
  return {
    fileType,
    url: file.url,
    fileName: file.fileName,
    newFileName: file.newFileName,
    originalFilename: file.originalFilename
  };
}

function removeFile(file: CollaborationFileCommand) {
  const index = formData.files.indexOf(file);
  if (index >= 0) {
    formData.files.splice(index, 1);
  }
}

function handlePreviewImage(file: UploadFile) {
  if (!file.url) return;
  previewImageUrl.value = file.url;
  isImagePreviewVisible.value = true;
}

function handleRemoveGoodsImage(file: UploadFile) {
  const target = goodsImages.value.find(item => getFileUrl(item) === file.url);
  if (target) {
    removeFile(target);
  }
}

function handlePreviewAttachment(file: UploadFile) {
  if (!file.url) {
    ElMessage.warning("文件地址不存在");
    return;
  }
  window.open(file.url, "_blank", "noopener,noreferrer");
}

function handleRemoveAttachment(file: UploadFile) {
  const target = attachments.value.find(item => getFileUrl(item) === file.url);
  if (target) {
    removeFile(target);
  }
}

function getFileName(file: CollaborationFileCommand) {
  return file.originalFilename || file.newFileName || "未命名文件";
}

function getFileUrl(file: CollaborationFileCommand) {
  if (file.url) return file.url;
  if (!file.fileName) return "";
  return `${import.meta.env.VITE_APP_BASE_API}${file.fileName}`;
}

async function setFixedTabContentHeight() {
  isMeasuringTabHeight.value = true;
  await waitForTabRender();
  const heights = tabNames.map(getTabContentHeight);
  tabContentHeight.value = Math.max(...heights, 0);
  isMeasuringTabHeight.value = false;
}

async function waitForTabRender() {
  await nextTick();
  await new Promise<void>(resolve => requestAnimationFrame(() => resolve()));
}

function getTabContentHeight(tabName: TabName) {
  return getTabPaneRef(tabName).value?.scrollHeight ?? 0;
}

function getTabPaneRef(tabName: TabName): Ref<HTMLElement | undefined> {
  const paneRefMap = {
    basic: basicPaneRef,
    tasks: tasksPaneRef,
    expenditures: expendituresPaneRef,
    settlements: settlementsPaneRef
  };
  return paneRefMap[tabName];
}

async function handleConfirm() {
  const isValid = await formRef.value?.validate().catch(() => false);
  if (!isValid) return false;
  return submitForm();
}

async function submitForm() {
  try {
    if (props.type === "add") {
      await addCollaborationRecordApi(formData);
    } else {
      await updateCollaborationRecordApi(
        formData as UpdateCollaborationRecordCommand
      );
    }
    ElMessage.success("提交成功");
    return true;
  } catch (e) {
    ElMessage.error((e as Error)?.message || "提交失败");
    return false;
  }
}

onMounted(handleOpened);

defineExpose({ handleConfirm });
</script>

<template>
  <el-form
    ref="formRef"
    class="record-form"
    :model="formData"
    :rules="rules"
    label-width="112px"
  >
    <el-tabs
      v-model="activeTab"
      class="record-tabs"
      :class="{ 'is-measuring': isMeasuringTabHeight }"
      :style="recordTabsStyle"
    >
      <el-tab-pane label="基本信息" name="basic">
        <div ref="basicPaneRef" class="tab-pane-content">
          <el-row :gutter="16">
            <el-col :span="12">
              <el-form-item prop="brand" label="品牌" required>
                <el-input v-model="formData.brand" placeholder="请输入品牌" />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item prop="goods" label="物品" required>
                <el-input v-model="formData.goods" placeholder="请输入物品" />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item
                prop="cooperationPlatform"
                label="合作平台"
                required
              >
                <el-select v-model="formData.cooperationPlatform" clearable>
                  <el-option
                    v-for="item in optionMap.cooperationPlatform"
                    :key="item"
                    :label="item"
                    :value="item"
                  />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item prop="imageReturnNum" label="返图数量" required>
                <el-input-number
                  :min="1"
                  controls-position="right"
                  v-model="formData.imageReturnNum"
                />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="留存方式">
                <el-select v-model="formData.retainedMethod">
                  <el-option
                    v-for="item in optionMap.retainedMethod"
                    :key="item"
                    :label="item"
                    :value="item"
                  />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="合作方式">
                <el-select v-model="formData.cooperatedMethod">
                  <el-option
                    v-for="item in optionMap.cooperatedMethod"
                    :key="item"
                    :label="item"
                    :value="item"
                  />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="购入方式">
                <el-select v-model="formData.purchaseMethod">
                  <el-option
                    v-for="item in optionMap.purchaseMethod"
                    :key="item"
                    :label="item"
                    :value="item"
                  />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="购入金额">
                <el-input-number
                  :min="0"
                  controls-position="right"
                  v-model="formData.purchasePrice"
                />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="购入平台">
                <el-select v-model="formData.purchasePlatform" clearable>
                  <el-option
                    v-for="item in optionMap.purchasePlatform"
                    :key="item"
                    :label="item"
                    :value="item"
                  />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="购入日期">
                <el-date-picker
                  v-model="formData.purchaseDate"
                  value-format="YYYY-MM-DD"
                  type="date"
                />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item prop="deadline" label="预完成日期" required>
                <el-date-picker
                  v-model="formData.deadline"
                  value-format="YYYY-MM-DD"
                  type="date"
                />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="稿费">
                <el-input-number
                  :min="0"
                  controls-position="right"
                  v-model="formData.remuneration"
                />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="16">
            <el-col :span="12">
              <el-form-item label="物品图片">
                <el-upload
                  multiple
                  accept="image/*"
                  class="goods-image-upload"
                  list-type="picture-card"
                  :file-list="goodsImageUploadFiles"
                  :http-request="option => handleUpload(option, 'GOODS_IMAGE')"
                  :on-preview="handlePreviewImage"
                  :on-remove="handleRemoveGoodsImage"
                >
                  <IconifyIconOffline class="upload-plus" :icon="Plus" />
                </el-upload>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="附件">
                <el-upload
                  multiple
                  class="attachment-upload"
                  :file-list="attachmentUploadFiles"
                  :http-request="option => handleUpload(option, 'ATTACHMENT')"
                  :on-preview="handlePreviewAttachment"
                  :on-remove="handleRemoveAttachment"
                >
                  <el-button>上传附件</el-button>
                </el-upload>
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="16">
            <el-col :span="12">
              <el-form-item label="拍摄要求">
                <el-input
                  type="textarea"
                  :rows="3"
                  v-model="formData.requirements"
                />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="备注">
                <el-input type="textarea" :rows="3" v-model="formData.remark" />
              </el-form-item>
            </el-col>
          </el-row>
        </div>
      </el-tab-pane>
      <el-tab-pane label="笔记任务" name="tasks">
        <div ref="tasksPaneRef" class="tab-pane-content">
          <el-button type="primary" plain @click="addTask">添加笔记</el-button>
          <div
            v-for="(item, index) in formData.tasks"
            :key="index"
            class="line-item"
          >
            <el-date-picker
              v-model="item.releaseDate"
              value-format="YYYY-MM-DD"
              type="date"
              placeholder="发布日期"
            />
            <el-button type="danger" link @click="removeTask(index)"
              >删除</el-button
            >
          </div>
        </div>
      </el-tab-pane>
      <el-tab-pane label="支出信息" name="expenditures">
        <div ref="expendituresPaneRef" class="tab-pane-content">
          <el-button type="primary" plain @click="addExpenditure"
            >添加支出</el-button
          >
          <div
            v-for="(item, index) in formData.expenditures"
            :key="index"
            class="line-item"
          >
            <el-date-picker
              v-model="item.spendDate"
              value-format="YYYY-MM-DD"
              type="date"
              placeholder="支出日期"
            />
            <el-input-number
              :min="0"
              controls-position="right"
              v-model="item.amount"
              placeholder="金额"
            />
            <el-select v-model="item.purpose" placeholder="用途" clearable>
              <el-option
                v-for="option in optionMap.expenditurePurpose"
                :key="option"
                :label="option"
                :value="option"
              />
            </el-select>
            <el-button type="danger" link @click="removeExpenditure(index)"
              >删除</el-button
            >
          </div>
        </div>
      </el-tab-pane>
      <el-tab-pane label="结款信息" name="settlements">
        <div ref="settlementsPaneRef" class="tab-pane-content">
          <el-button type="primary" plain @click="addSettlement"
            >添加结款</el-button
          >
          <div
            v-for="(item, index) in formData.settlements"
            :key="index"
            class="line-item"
          >
            <el-date-picker
              v-model="item.settleDate"
              value-format="YYYY-MM-DD"
              type="date"
              placeholder="结款日期"
            />
            <el-select v-model="item.method" placeholder="方式" clearable>
              <el-option
                v-for="option in optionMap.settlementMethod"
                :key="option"
                :label="option"
                :value="option"
              />
            </el-select>
            <el-input-number
              :min="0"
              controls-position="right"
              v-model="item.income"
              placeholder="金额"
            />
            <el-select v-model="item.purpose" placeholder="用途" clearable>
              <el-option
                v-for="option in optionMap.settlementPurpose"
                :key="option"
                :label="option"
                :value="option"
              />
            </el-select>
            <el-button type="danger" link @click="removeSettlement(index)"
              >删除</el-button
            >
          </div>
        </div>
      </el-tab-pane>
    </el-tabs>
  </el-form>
  <el-dialog v-model="isImagePreviewVisible" append-to-body>
    <img class="preview-image" :src="previewImageUrl" alt="" />
  </el-dialog>
</template>

<style scoped lang="scss">
.line-item {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-top: 12px;
}

.record-form {
  :deep(.el-row .el-select),
  :deep(.el-row .el-date-editor.el-input),
  :deep(.el-row .el-input-number) {
    width: 100%;
  }

  :deep(.el-input-number .el-input__inner) {
    text-align: left;
  }
}

.record-tabs {
  :deep(.el-tabs__content) {
    height: var(--record-tab-content-height, auto);
    max-height: calc(88vh - 190px);
    overflow-y: auto;
  }

  &.is-measuring {
    :deep(.el-tabs__content) {
      position: relative;
      visibility: hidden;
    }

    :deep(.el-tab-pane) {
      position: absolute;
      display: block !important;
      width: 100%;
      visibility: hidden;
    }

    :deep(.el-tab-pane.is-active) {
      position: static;
    }
  }
}

.tab-pane-content {
  padding-right: 4px;
}

.goods-image-upload {
  :deep(.el-upload--picture-card),
  :deep(.el-upload-list--picture-card .el-upload-list__item) {
    width: 96px;
    height: 96px;
    line-height: 96px;
  }
}

.upload-plus {
  font-size: 24px;
  color: var(--el-text-color-placeholder);
}

.attachment-upload {
  width: 100%;
  max-width: 100%;
}

.preview-image {
  display: block;
  max-width: 100%;
  margin: 0 auto;
}
</style>
