<script setup lang="tsx">
/* eslint-disable no-void */
import { computed, markRaw, reactive, ref, watch } from 'vue';
import { ElMessageBox, ElTag, ElTooltip } from 'element-plus';
import dayjs from 'dayjs';
import {
  fetchDeleteWeeklyReport,
  fetchExportWeeklyReportContent,
  fetchGetTeamReportSummary,
  fetchGetWeeklyReportPage,
  fetchSubmitWeeklyReport
} from '@/service/api';
import { useAuth } from '@/hooks/business/auth';
import { useUIPaginatedTable } from '@/hooks/common/table';
import BusinessTableActionCell, { type BusinessTableAction } from '@/components/custom/business-table-action-cell';
import { type TeamViewContext } from '@/views/personal-center/shared/team-dashboard';
import {
  type WorkReportRow,
  createWeeklySearchParams,
  createWorkReportContentExportFallbackName,
  downloadBlob,
  formatDateTime,
  formatEmptyText,
  formatPeriod,
  formatPeriodDateRange,
  formatWeeklyPeriodLabel,
  getWorkReportStatusLabel,
  getWorkReportTypeDisplayLabel,
  resolveExportFilename,
  resolveWorkReportStatusTagType,
  transformWorkReportPage
} from '../shared/types';
import { buildWeeklyPeriodFromDate, normalizeWeeklySearchRange, resolveWorkReportSummaryPeriod } from '../shared/utils';
import WeeklyReportSearch from './modules/search-panel.vue';
import IconMdiDeleteOutline from '~icons/mdi/delete-outline';
import IconMdiEyeOutline from '~icons/mdi/eye-outline';
import IconMdiFileDocumentCheckOutline from '~icons/mdi/file-document-check-outline';
import IconMdiPencilOutline from '~icons/mdi/pencil-outline';
import IconMdiSendOutline from '~icons/mdi/send-outline';
import IconMdiDownloadOutline from '~icons/mdi/download-outline';

defineOptions({ name: 'WeeklyWorkReportIndex' });

const props = defineProps<{
  teamContext?: TeamViewContext | null;
  subordinateOptions?: Array<{ label: string; value: string }>;
}>();

const emit = defineEmits<{
  (e: 'create'): void;
  (e: 'edit', row: WorkReportRow): void;
  (e: 'detail', row: WorkReportRow): void;
  (e: 'approvalRecord', row: WorkReportRow): void;
}>();

const { hasAuth } = useAuth();
const exporting = ref(false);
const selectedRows = ref<Api.WorkReport.Weekly.WeeklyReport[]>([]);
const searchParams = reactive(createWeeklySearchParams());
const teamSummaryLoading = ref(false);
const teamSummary = ref<Api.WorkReport.Common.TeamReportSummary | null>(null);

const ACTION_ICON_MAP = {
  detail: markRaw(IconMdiEyeOutline),
  edit: markRaw(IconMdiPencilOutline),
  submit: markRaw(IconMdiSendOutline),
  delete: markRaw(IconMdiDeleteOutline),
  approvalRecord: markRaw(IconMdiFileDocumentCheckOutline),
  export: markRaw(IconMdiDownloadOutline)
};

const isTeamMode = computed(() => props.teamContext?.mode === 'team');
const isTeamRootSelected = computed(() => Boolean(isTeamMode.value && props.teamContext?.isRootSelected));
const currentTeamReporterIds = computed(() => {
  if (!isTeamMode.value) {
    return null;
  }

  if (isTeamRootSelected.value) {
    return [];
  }

  return props.teamContext?.selectedUserIds ?? [];
});
const resolvedTeamReporterIds = computed(() => {
  if (!isTeamMode.value) {
    return undefined;
  }

  if (searchParams.reporterIds?.length) {
    return searchParams.reporterIds;
  }

  return currentTeamReporterIds.value;
});
const reportTitle = computed(() => getWorkReportTypeDisplayLabel('weekly', isTeamMode.value));
const normalizedPeriodRange = computed(() => normalizeWeeklySearchRange(searchParams.periodStartDate));
const table = useUIPaginatedTable<
  Awaited<ReturnType<typeof fetchGetWeeklyReportPage>>,
  Api.WorkReport.Weekly.WeeklyReport
>({
  paginationProps: { currentPage: searchParams.pageNo, pageSize: searchParams.pageSize },
  api: () =>
    fetchGetWeeklyReportPage({
      ...searchParams,
      periodStartDate: normalizedPeriodRange.value,
      reporterIds: resolvedTeamReporterIds.value
    }),
  transform: response => transformWorkReportPage(response, searchParams.pageNo ?? 1, searchParams.pageSize ?? 10),
  onPaginationParamsChange: params => {
    searchParams.pageNo = params.currentPage ?? 1;
    searchParams.pageSize = params.pageSize ?? 10;
  },
  columns: () => {
    const cols: UI.TableColumn<Api.WorkReport.Weekly.WeeklyReport>[] = [
      { prop: 'index', type: 'index', label: '序号', width: 64 },
      {
        prop: 'periodLabel',
        label: '周期',
        minWidth: 150,
        formatter: row => {
          const periodText = formatWeeklyPeriodLabel(row);
          const weekLabel = formatPeriodDateRange(row);
          if (!weekLabel || weekLabel === '--') return periodText;
          return (
            <ElTooltip content={weekLabel} placement="top">
              <span>{periodText}</span>
            </ElTooltip>
          );
        }
      }
    ];

    if (isTeamMode.value) {
      cols.push({ prop: 'reporterName', label: '提交人', minWidth: 100, showOverflowTooltip: true });
    }

    cols.push(
      {
        prop: 'reporterDeptName',
        label: '部门',
        minWidth: 80,
        showOverflowTooltip: true,
        formatter: row => row.reporterDeptName || '--'
      },
      { prop: 'supervisorName', label: '直属上级', minWidth: 80 },
      { prop: 'totalWorkHours', label: '总工时', minWidth: 80, formatter: row => formatEmptyText(row.totalWorkHours) },
      {
        prop: 'isBusinessTrip',
        label: '出差',
        minWidth: 80,
        align: 'center',
        formatter: row => (row.isBusinessTrip ? '是' : '否')
      },
      {
        prop: 'totalTravelDays',
        label: '出差天数',
        minWidth: 90,
        formatter: row => formatEmptyText(row.totalTravelDays)
      },
      {
        prop: 'statusCode',
        label: '状态',
        minWidth: 80,
        align: 'center',
        formatter: row => (
          <ElTag type={resolveWorkReportStatusTagType(row.statusCode)}>
            {getWorkReportStatusLabel(row.statusCode, row.statusName)}
          </ElTag>
        )
      },
      { prop: 'submitTime', label: '提交时间', minWidth: 100, formatter: row => formatDateTime(row.submitTime) },
      { prop: 'approvalTime', label: '审批时间', minWidth: 100, formatter: row => formatDateTime(row.approvalTime) },
      {
        prop: 'operate',
        label: '操作',
        width: isTeamMode.value ? 140 : 180,
        align: 'center',
        fixed: 'right',
        formatter: row => <BusinessTableActionCell actions={getRowActions(row)} variant="icon" />
      }
    );

    return cols;
  }
});

// 团队统计始终使用当前周期（本周），不跟随列表第一条数据的周期
const summaryPeriod = computed(() =>
  resolveWorkReportSummaryPeriod('weekly', {
    periodRange: normalizedPeriodRange.value
  })
);
const summaryPeriodKeys = computed(() => {
  const dateRange = normalizedPeriodRange.value;
  const fallbackKey = summaryPeriod.value.periodKey;

  if (!dateRange?.length) {
    return fallbackKey ? [fallbackKey] : [];
  }

  const [startDate, endDate] = dateRange;
  const start = dayjs(startDate);
  const end = dayjs(endDate || startDate);

  if (!start.isValid() || !end.isValid()) {
    return fallbackKey ? [fallbackKey] : [];
  }

  const keys: string[] = [];
  const startBoundary = start.startOf('day');
  const endBoundary = end.endOf('day');

  for (
    let cursor = start.startOf('isoWeek');
    cursor.isBefore(endBoundary, 'day') || cursor.isSame(endBoundary, 'day');
    cursor = cursor.add(1, 'week')
  ) {
    if (!cursor.isBefore(startBoundary, 'day')) {
      keys.push(buildWeeklyPeriodFromDate(cursor).periodKey);
    }
  }

  return keys;
});
const hasSearchedDateRange = computed(() => searchParams.periodStartDate?.length === 2);

watch(
  () => isTeamMode.value,
  () => {
    table.reloadColumns();
  }
);

function getRowActions(row: Api.WorkReport.Weekly.WeeklyReport): BusinessTableAction[] {
  const actions: BusinessTableAction[] = [
    {
      key: 'detail',
      label: '查看',
      buttonType: 'primary',
      icon: ACTION_ICON_MAP.detail,
      onClick: () => emit('detail', row)
    }
  ];

  if (isTeamMode.value) {
    actions.push({
      key: 'export',
      label: '导出',
      buttonType: 'success',
      icon: ACTION_ICON_MAP.export,
      onClick: () =>
        exportReportContent(
          {
            exportAll: false,
            ids: [row.id]
          },
          1
        )
    });

    if (['approved', 'rejected'].includes(row.statusCode)) {
      actions.push({
        key: 'approval-record',
        label: '审批记录',
        buttonType: 'info',
        icon: ACTION_ICON_MAP.approvalRecord,
        onClick: () => emit('approvalRecord', row)
      });
    }

    return actions;
  }

  if (['draft', 'rejected'].includes(row.statusCode) && row.allowEdit && hasAuth('project:work-report:update')) {
    actions.push({
      key: 'edit',
      label: '编辑',
      buttonType: 'primary',
      icon: ACTION_ICON_MAP.edit,
      onClick: () => emit('edit', row)
    });
    actions.push({
      key: 'submit',
      label: row.statusCode === 'draft' ? '提交' : '重新提交',
      buttonType: 'success',
      icon: ACTION_ICON_MAP.submit,
      onClick: () => handleSubmitReport(row)
    });
  }

  if (row.statusCode === 'draft' && hasAuth('project:work-report:delete')) {
    actions.push({
      key: 'delete',
      label: '删除',
      buttonType: 'danger',
      icon: ACTION_ICON_MAP.delete,
      onClick: () => handleDelete(row)
    });
  }

  if (['approved', 'rejected'].includes(row.statusCode)) {
    actions.push({
      key: 'approval-record',
      label: '审批记录',
      buttonType: 'info',
      icon: ACTION_ICON_MAP.approvalRecord,
      onClick: () => emit('approvalRecord', row)
    });
  }

  return actions;
}

async function reload(page?: number) {
  await table.getDataByPage(page ?? searchParams.pageNo ?? 1);
  await loadTeamSummary();
}

function resetSearchParams() {
  const pageSize = searchParams.pageSize ?? 10;
  Object.assign(searchParams, createWeeklySearchParams(), { pageSize });
  reload(1);
}

function handleSearch() {
  reload(1);
}

async function handleSubmitReport(row: Api.WorkReport.Weekly.WeeklyReport) {
  try {
    await ElMessageBox.confirm('确认提交该报告吗？', '提交确认', {
      type: 'warning',
      confirmButtonText: row.statusCode === 'draft' ? '确认提交' : '确认重新提交',
      cancelButtonText: '取消'
    });
  } catch {
    return;
  }

  const result = await fetchSubmitWeeklyReport(row.id);

  if (result.error) return;
  window.$message?.success('工作报告已提交');
  await reload();
}

async function handleDelete(row: Api.WorkReport.Weekly.WeeklyReport) {
  try {
    await ElMessageBox.confirm(`确认删除该报告吗？`, '删除确认', {
      type: 'warning',
      confirmButtonText: '确认',
      cancelButtonText: '取消'
    });
  } catch {
    return;
  }

  const result = await fetchDeleteWeeklyReport(row.id);

  if (result.error) return;

  window.$message?.success('工作报告已删除');
  await reload();
}

function handleSelectionChange(rows: Api.WorkReport.Weekly.WeeklyReport[]) {
  selectedRows.value = rows;
}

function createExportSearchParams() {
  const { pageNo: _pageNo, pageSize: _pageSize, ...params } = searchParams;
  return {
    ...params,
    periodStartDate: normalizedPeriodRange.value,
    reporterIds: resolvedTeamReporterIds.value
  };
}

async function exportReportContent(
  params: Api.WorkReport.Common.ContentExportParams<Api.WorkReport.Weekly.WeeklyReportSearchParams>,
  reportCount: number
) {
  exporting.value = true;
  const result = await fetchExportWeeklyReportContent(params);
  exporting.value = false;

  if (result.error || !result.data) return;

  const fallbackName = createWorkReportContentExportFallbackName('weekly', reportCount);
  downloadBlob(result.data, resolveExportFilename(result, fallbackName));
}

async function handleExportSelected() {
  if (!selectedRows.value.length) {
    window.$message?.warning('请选择要导出的报告');
    return;
  }

  await exportReportContent(
    {
      exportAll: false,
      ids: selectedRows.value.map(item => item.id)
    },
    selectedRows.value.length
  );
}

async function handleExportAll() {
  const total = table.mobilePagination.value.total || 0;
  if (!total) {
    window.$message?.warning('暂无可导出的报告');
    return;
  }

  await exportReportContent(
    {
      ...createExportSearchParams(),
      exportAll: true,
      ids: []
    },
    total
  );
}

async function handleExportCommand(command: 'selected' | 'all') {
  if (command === 'selected') {
    await handleExportSelected();
    return;
  }

  await handleExportAll();
}

async function loadTeamSummary() {
  if (!isTeamRootSelected.value) {
    teamSummaryLoading.value = false;
    teamSummary.value = null;
    return;
  }

  const dateRange = normalizedPeriodRange.value;
  const summaryParams: Api.WorkReport.Common.TeamReportSummaryParams = { reportType: 'weekly' };

  if (dateRange?.length === 2) {
    summaryParams.periodStartDate = dateRange[0];
    summaryParams.periodEndDate = dateRange[1];
  } else {
    summaryParams.periodKey = summaryPeriod.value.periodKey;
  }

  teamSummaryLoading.value = true;
  const { error, data } = await fetchGetTeamReportSummary(summaryParams);
  teamSummaryLoading.value = false;

  teamSummary.value = error || !data ? null : data;
}

defineExpose({
  reload,
  teamSummary,
  teamSummaryLoading,
  summaryPeriod,
  summaryPeriodKeys,
  hasSearchedDateRange,
  loadTeamSummary
});
</script>

<template>
  <div class="flex-col-stretch gap-16px overflow-hidden">
    <WeeklyReportSearch
      v-model:model="searchParams"
      :team-mode="isTeamMode"
      :subordinate-options="props.subordinateOptions"
      @reset="resetSearchParams"
      @search="handleSearch"
    />

    <ElCard class="flex-1-hidden card-wrapper" body-class="business-table-card-body">
      <template #header>
        <div class="flex flex-wrap items-center justify-between gap-12px">
          <div class="flex items-center gap-10px">
            <p class="text-16px font-600">{{ reportTitle }}</p>
            <ElTag effect="plain">{{ table.mobilePagination.value.total || 0 }}</ElTag>
          </div>

          <TableHeaderOperation
            v-model:columns="table.columnChecks.value"
            :loading="table.loading.value"
            @refresh="reload()"
          >
            <template #default>
              <ElDropdown v-auth="'project:work-report:export'" trigger="click" @command="handleExportCommand">
                <ElButton plain :loading="exporting">
                  <template #icon>
                    <icon-mdi-download class="text-icon" />
                  </template>
                  导出
                </ElButton>
                <template #dropdown>
                  <ElDropdownMenu>
                    <ElDropdownItem command="selected" :disabled="exporting || !selectedRows.length">
                      导出选中
                    </ElDropdownItem>
                    <ElDropdownItem command="all" :disabled="exporting">导出全部</ElDropdownItem>
                  </ElDropdownMenu>
                </template>
              </ElDropdown>
              <ElButton
                v-if="!isTeamMode"
                v-auth="'project:work-report:create'"
                plain
                type="primary"
                @click="emit('create')"
              >
                <template #icon>
                  <icon-ic-round-plus class="text-icon" />
                </template>
                新增
              </ElButton>
            </template>
          </TableHeaderOperation>
        </div>
      </template>

      <div class="flex-1">
        <ElTable
          v-loading="table.loading.value"
          height="100%"
          border
          row-key="id"
          :data="table.data.value"
          @selection-change="handleSelectionChange"
        >
          <ElTableColumn type="selection" width="48" />
          <template v-for="col in table.columns.value" :key="String(col.prop)">
            <ElTableColumn v-bind="col" />
          </template>
        </ElTable>
      </div>

      <div class="mt-20px flex justify-end">
        <ElPagination
          v-if="table.mobilePagination.value.total"
          layout="total,prev,pager,next,sizes"
          v-bind="table.mobilePagination.value"
          @current-change="table.mobilePagination.value['current-change']"
          @size-change="table.mobilePagination.value['size-change']"
        />
      </div>
    </ElCard>
  </div>
</template>
