<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue';
import {
  fetchGetMyOwnedProjectPage,
  fetchGetMyParticipatedProjectPage,
  fetchGetProjectExecutionPage
} from '@/service/api';
import { useForm, useFormRules } from '@/hooks/common/form';
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';

defineOptions({ name: 'PersonalItemBindExecutionDialog' });

interface Props {
  selectedCount: number;
  submitLoading?: boolean;
}

interface Emits {
  (e: 'submit', payload: { executionId: string }): void;
}

const props = withDefaults(defineProps<Props>(), {
  submitLoading: false
});

const emit = defineEmits<Emits>();

const visible = defineModel<boolean>('visible', {
  default: false
});

const { formRef, validate } = useForm();
const { createRequiredRule } = useFormRules();

interface ProjectOption {
  label: string;
  value: string;
}

interface ExecutionOption {
  label: string;
  value: string;
}

const projectLoading = ref(false);
const executionLoading = ref(false);
const projectOptions = ref<ProjectOption[]>([]);
const executionOptions = ref<ExecutionOption[]>([]);
const loading = computed(() => projectLoading.value || executionLoading.value);

const model = reactive({
  projectId: '',
  executionId: ''
});

const rules = computed(
  () =>
    ({
      projectId: [createRequiredRule('请选择项目')],
      executionId: [createRequiredRule('请选择执行')]
    }) satisfies Record<string, App.Global.FormRule[]>
);

function createProjectOptions(
  participated: Api.Project.MyParticipatedProjectItem[],
  owned: Api.Project.MyOwnedProjectItem[]
): ProjectOption[] {
  const optionMap = new Map<string, ProjectOption>();

  owned.forEach(item => {
    if (!item.id || !item.name?.trim()) return;
    optionMap.set(item.id, {
      label: item.name.trim(),
      value: item.id
    });
  });

  participated.forEach(item => {
    if (!item.id || !item.name?.trim()) return;
    if (item.statusCode === 'completed' || item.statusCode === 'cancelled' || item.statusCode === 'archived') {
      return;
    }
    if (!optionMap.has(item.id)) {
      optionMap.set(item.id, {
        label: item.name.trim(),
        value: item.id
      });
    }
  });

  return Array.from(optionMap.values());
}

async function loadProjectOptions() {
  projectLoading.value = true;
  const [participatedResult, ownedResult] = await Promise.all([
    fetchGetMyParticipatedProjectPage({ pageNo: 1, pageSize: -1 }),
    fetchGetMyOwnedProjectPage({ pageNo: 1, pageSize: -1 })
  ]);
  projectLoading.value = false;

  if (participatedResult.error || ownedResult.error || !participatedResult.data || !ownedResult.data) {
    projectOptions.value = [];
    executionOptions.value = [];
    return;
  }

  projectOptions.value = createProjectOptions(participatedResult.data.list, ownedResult.data.list);
}

async function loadExecutionOptions(projectId: string) {
  if (!projectId) {
    executionOptions.value = [];
    return;
  }

  executionLoading.value = true;
  const { error, data } = await fetchGetProjectExecutionPage(projectId, {
    pageNo: 1,
    pageSize: -1
  });
  executionLoading.value = false;

  if (error || !data) {
    executionOptions.value = [];
    return;
  }

  executionOptions.value = data.list
    .filter(item => !item.terminal && item.statusCode !== 'completed' && item.statusCode !== 'cancelled')
    .map(item => ({
      label: item.executionName,
      value: item.id
    }));
}

async function initDialog() {
  model.projectId = '';
  model.executionId = '';
  executionOptions.value = [];
  await loadProjectOptions();
  formRef.value?.clearValidate();
}

async function handleConfirm() {
  await validate();

  emit('submit', {
    executionId: model.executionId
  });
}

watch(
  () => visible.value,
  value => {
    if (value) {
      initDialog();
    }
  }
);

watch(
  () => model.projectId,
  async (projectId, previousProjectId) => {
    if (projectId === previousProjectId) return;

    model.executionId = '';

    if (!projectId) {
      executionOptions.value = [];
      formRef.value?.clearValidate('executionId');
      return;
    }

    await loadExecutionOptions(projectId);
    formRef.value?.clearValidate('executionId');
  }
);
</script>

<template>
  <BusinessFormDialog
    v-model="visible"
    title="批量关联执行"
    preset="md"
    :loading="loading"
    :confirm-loading="props.submitLoading"
    @confirm="handleConfirm"
  >
    <ElAlert
      :title="`已选中 ${props.selectedCount} 条我的事项，关联成功后这些事项会从当前列表移除。`"
      type="info"
      :closable="false"
      class="mb-16px"
    />

    <ElForm ref="formRef" :model="model" :rules="rules" label-position="top" :validate-on-rule-change="false">
      <ElRow :gutter="16">
        <ElCol :span="12">
          <ElFormItem label="项目" prop="projectId">
            <ElSelect
              v-model="model.projectId"
              clearable
              filterable
              placeholder="请选择项目"
              class="w-full"
              :loading="projectLoading"
            >
              <ElOption
                v-for="option in projectOptions"
                :key="option.value"
                :label="option.label"
                :value="option.value"
              />
            </ElSelect>
          </ElFormItem>
        </ElCol>
        <ElCol :span="12">
          <ElFormItem label="执行" prop="executionId">
            <ElSelect
              v-model="model.executionId"
              clearable
              filterable
              placeholder="请选择执行"
              class="w-full"
              :loading="executionLoading"
              :disabled="!model.projectId"
            >
              <ElOption
                v-for="option in executionOptions"
                :key="option.value"
                :label="option.label"
                :value="option.value"
              />
            </ElSelect>
          </ElFormItem>
        </ElCol>
      </ElRow>
    </ElForm>
  </BusinessFormDialog>
</template>

<style scoped></style>
