import dayjs from 'dayjs';
import { WEB_SERVICE_PREFIX } from '@/constants/service';
import { request } from '../request';
import {
  type ServiceRequestResult,
  mapServiceResult,
  normalizeNullableStringId,
  normalizeStringId,
  safeJsonRequestConfig
} from './shared';

const TEMPLATE_PREFIX = `${WEB_SERVICE_PREFIX}/project/performance-templates`;
const SHEET_PREFIX = `${WEB_SERVICE_PREFIX}/project/performance-sheets`;
const TEAM_PREFIX = `${SHEET_PREFIX}/team`;

type StringIdResponse = string | number;

type TemplateResponse = Omit<Api.Performance.Template.Template, 'id' | 'fileId' | 'uploadUserId' | 'activeFlag'> & {
  id: StringIdResponse;
  fileId: StringIdResponse;
  uploadUserId: StringIdResponse;
  employeeId?: StringIdResponse | null;
  employeeDeptId?: StringIdResponse | null;
  activeFlag?: boolean | number | string | null;
};

type TemplatePageResponse = {
  total: number | string;
  list: TemplateResponse[];
};

type TemplateUploadScopeResponse = {
  orgLeader?: boolean | number | string | null;
  employeeCount?: number | string | null;
  employees?: Array<{
    employeeId: StringIdResponse;
    employeeName: string;
    employeeDeptId?: StringIdResponse | null;
    employeeDeptName?: string | null;
  }> | null;
};

type TemplateBatchImportResponse = {
  successCount?: number | string | null;
  failureCount?: number | string | null;
  successes?: Array<{
    employeeId: StringIdResponse;
    employeeName: string;
    templateId: StringIdResponse;
    sourceFileName: string;
    sheetName?: string | null;
  }> | null;
  failures?: Array<{
    sourceFileName: string;
    sheetName?: string | null;
    reason: string;
  }> | null;
};

type SheetResponse = Omit<
  Api.Performance.Sheet.Sheet,
  'id' | 'employeeId' | 'employeeDeptId' | 'managerId' | 'templateId' | 'fileId'
> & {
  id: StringIdResponse;
  employeeId: StringIdResponse;
  employeeDeptId: StringIdResponse;
  managerId: StringIdResponse;
  templateId: StringIdResponse;
  fileId?: StringIdResponse | null;
};

type SheetPageResponse = {
  total: number | string;
  list: SheetResponse[];
};

type ImportZipResultResponse = Omit<Api.Performance.Sheet.ImportZipResult, 'messages'> & {
  workbookCount?: number | string | null;
  sheetCount?: number | string | null;
  successCount?: number | string | null;
  skippedCount?: number | string | null;
  failedCount?: number | string | null;
  messages?: string[] | null;
};

type StatusLogResponse = Omit<Api.Performance.Sheet.StatusLog, 'id' | 'sheetId' | 'operatorUserId'> & {
  id: StringIdResponse;
  sheetId: StringIdResponse;
  operatorUserId: StringIdResponse;
};

type ResponseRecordResponse = Omit<
  Api.Performance.Sheet.ResponseRecord,
  'id' | 'sheetId' | 'statusLogId' | 'responderUserId'
> & {
  id: StringIdResponse;
  sheetId: StringIdResponse;
  statusLogId: StringIdResponse;
  responderUserId: StringIdResponse;
};

type MonthlyResultResponse = Omit<Api.Performance.Sheet.MonthlyResult, 'sheetId' | 'employeeId'> & {
  sheetId?: StringIdResponse | null;
  employeeId: StringIdResponse;
};

type PrefillResponse = Omit<Api.Performance.Sheet.PrefillData, 'sourceSheetId' | 'cellValues'> & {
  sourceSheetId?: StringIdResponse | null;
  cellValues?: Record<string, string | number | null | undefined> | null;
};

type TeamSummaryResponse = Omit<
  Api.Performance.Team.Summary,
  | 'expectedSheetCount'
  | 'pendingSendCount'
  | 'pendingConfirmCount'
  | 'pendingSendUsers'
  | 'pendingConfirmUsers'
  | 'deptOrgAverages'
> & {
  expectedSheetCount?: number | string | null;
  pendingSendCount?: number | string | null;
  pendingConfirmCount?: number | string | null;
  pendingSendUsers?: Array<
    Omit<Api.Performance.Team.PendingSendUser, 'userId' | 'managerUserId' | 'sheetId'> & {
      userId: StringIdResponse;
      managerUserId?: StringIdResponse | null;
      sheetId?: StringIdResponse | null;
    }
  > | null;
  pendingConfirmUsers?: Array<
    Omit<Api.Performance.Team.PendingConfirmUser, 'userId' | 'sheetId'> & {
      userId: StringIdResponse;
      sheetId: StringIdResponse;
    }
  > | null;
  deptOrgAverages?: Array<
    Omit<Api.Performance.Team.DeptOrgAverage, 'deptId' | 'confirmedCount'> & {
      deptId: StringIdResponse;
      confirmedCount?: number | string | null;
    }
  > | null;
};

function normalizeBooleanFlag(value: boolean | number | string | null | undefined) {
  if (typeof value === 'boolean') return value;
  if (typeof value === 'number') return value === 1;
  if (typeof value === 'string') {
    const normalized = value.trim().toLowerCase();

    return !['', '0', 'false', 'n', 'no'].includes(normalized);
  }

  return false;
}

function normalizeTotal(value: number | string | null | undefined) {
  const total = Number(value ?? 0);

  return Number.isFinite(total) ? Math.max(0, total) : 0;
}

function normalizeTemplate(response: TemplateResponse): Api.Performance.Template.Template {
  return {
    ...response,
    id: normalizeStringId(response.id),
    fileId: normalizeStringId(response.fileId),
    employeeId: normalizeNullableStringId(response.employeeId),
    employeeDeptId: normalizeNullableStringId(response.employeeDeptId),
    uploadUserId: normalizeStringId(response.uploadUserId),
    activeFlag: normalizeBooleanFlag(response.activeFlag),
    remark: response.remark ?? null,
    scoreCellMapping: response.scoreCellMapping ?? null
  };
}

function normalizeTemplateUploadScope(response: TemplateUploadScopeResponse): Api.Performance.Template.UploadScope {
  return {
    orgLeader: normalizeBooleanFlag(response.orgLeader),
    employeeCount: normalizeTotal(response.employeeCount),
    employees: (response.employees || []).map(item => ({
      employeeId: normalizeStringId(item.employeeId),
      employeeName: item.employeeName,
      employeeDeptId: normalizeNullableStringId(item.employeeDeptId),
      employeeDeptName: item.employeeDeptName ?? null
    }))
  };
}

function normalizeTemplateBatchImportResult(
  response: TemplateBatchImportResponse
): Api.Performance.Template.BatchImportResult {
  return {
    successCount: normalizeTotal(response.successCount),
    failureCount: normalizeTotal(response.failureCount),
    successes: (response.successes || []).map(item => ({
      employeeId: normalizeStringId(item.employeeId),
      employeeName: item.employeeName,
      templateId: normalizeStringId(item.templateId),
      sourceFileName: item.sourceFileName,
      sheetName: item.sheetName ?? null
    })),
    failures: (response.failures || []).map(item => ({
      sourceFileName: item.sourceFileName,
      sheetName: item.sheetName ?? null,
      reason: item.reason
    }))
  };
}

function normalizeSheet(response: SheetResponse): Api.Performance.Sheet.Sheet {
  return {
    ...response,
    id: normalizeStringId(response.id),
    employeeId: normalizeStringId(response.employeeId),
    employeeDeptId: normalizeStringId(response.employeeDeptId),
    managerId: normalizeStringId(response.managerId),
    templateId: normalizeStringId(response.templateId),
    fileId: normalizeNullableStringId(response.fileId),
    fileName: response.fileName ?? null,
    statusName: response.statusName || response.statusCode,
    signOffStatus: response.signOffStatus ?? null,
    signOffStatusName: response.signOffStatusName ?? null,
    actualScoreTotal: response.actualScoreTotal ?? null,
    baseScoreTotal: response.baseScoreTotal ?? null,
    extraScoreTotal: response.extraScoreTotal ?? null,
    sentTime: response.sentTime ?? null,
    confirmedTime: response.confirmedTime ?? null,
    rejectedTime: response.rejectedTime ?? null,
    lastStatusReason: response.lastStatusReason ?? null,
    createTime: response.createTime ?? null,
    updateTime: response.updateTime ?? null
  };
}

function normalizeStatusLog(response: StatusLogResponse): Api.Performance.Sheet.StatusLog {
  return {
    ...response,
    id: normalizeStringId(response.id),
    sheetId: normalizeStringId(response.sheetId),
    operatorUserId: normalizeStringId(response.operatorUserId),
    reason: response.reason ?? null,
    remark: response.remark ?? null
  };
}

function normalizeResponseRecord(response: ResponseRecordResponse): Api.Performance.Sheet.ResponseRecord {
  return {
    ...response,
    id: normalizeStringId(response.id),
    sheetId: normalizeStringId(response.sheetId),
    statusLogId: normalizeStringId(response.statusLogId),
    responderUserId: normalizeStringId(response.responderUserId),
    opinion: response.opinion ?? null
  };
}

function normalizeMonthlyResult(response: MonthlyResultResponse): Api.Performance.Sheet.MonthlyResult {
  return {
    ...response,
    sheetId: normalizeNullableStringId(response.sheetId),
    employeeId: normalizeStringId(response.employeeId),
    actualScoreTotal: response.actualScoreTotal ?? null,
    baseScoreTotal: response.baseScoreTotal ?? null,
    extraScoreTotal: response.extraScoreTotal ?? null,
    statusCode: response.statusCode ?? null
  };
}

function normalizePrefillData(response: PrefillResponse): Api.Performance.Sheet.PrefillData {
  const cellValues = Object.fromEntries(
    Object.entries(response.cellValues || {}).flatMap(([address, value]) => {
      const normalizedAddress = String(address || '')
        .trim()
        .toUpperCase();

      if (!normalizedAddress || value === null || value === undefined) {
        return [];
      }

      return [[normalizedAddress, String(value)]];
    })
  );

  return {
    sourceSheetId: normalizeNullableStringId(response.sourceSheetId),
    sourcePeriodMonth: response.sourcePeriodMonth ?? null,
    cellValues
  };
}

function normalizeTeamSummary(response: TeamSummaryResponse): Api.Performance.Team.Summary {
  return {
    ...response,
    expectedSheetCount: normalizeTotal(response.expectedSheetCount),
    pendingSendCount: normalizeTotal(response.pendingSendCount),
    pendingConfirmCount: normalizeTotal(response.pendingConfirmCount),
    pendingSendUsers: (response.pendingSendUsers || []).map(item => ({
      ...item,
      userId: normalizeStringId(item.userId),
      managerUserId: normalizeNullableStringId(item.managerUserId),
      sheetId: normalizeNullableStringId(item.sheetId),
      statusCode: item.statusCode ?? null
    })),
    pendingConfirmUsers: (response.pendingConfirmUsers || []).map(item => ({
      ...item,
      userId: normalizeStringId(item.userId),
      sheetId: normalizeStringId(item.sheetId),
      sentTime: item.sentTime ?? null
    })),
    deptOrgAverages: (response.deptOrgAverages || []).map(item => ({
      ...item,
      deptId: normalizeStringId(item.deptId),
      averageScore: item.averageScore ?? null,
      confirmedCount: normalizeTotal(item.confirmedCount)
    }))
  };
}

function appendValue(query: URLSearchParams, key: string, value: unknown) {
  if (value === null || value === undefined || value === '') return;

  if (Array.isArray(value)) {
    if (!value.length) {
      query.append(key, '');
      return;
    }

    value.forEach(item => appendValue(query, key, item));
    return;
  }

  query.append(key, String(value));
}

export function formatToYYYYMM(value?: string | null) {
  if (!value) return '';

  const d = dayjs(value);

  return d.isValid() ? d.format('YYYY-MM') : value.slice(0, 7);
}

function createSheetQuery(params: Api.Performance.Sheet.SearchParams = {}) {
  const query = new URLSearchParams();

  query.append('pageNo', String(params.pageNo ?? 1));
  query.append('pageSize', String(params.pageSize ?? 10));
  appendValue(query, 'employeeIds', params.employeeIds);
  // 将 periodMonthRange 拆为 periodMonthStart / periodMonthEnd
  if (params.periodMonthRange?.length === 2) {
    appendValue(query, 'periodMonthStart', formatToYYYYMM(params.periodMonthRange[0]));
    appendValue(query, 'periodMonthEnd', formatToYYYYMM(params.periodMonthRange[1]));
  }
  // employeeId 单选追加到 employeeIds
  if (params.employeeId) {
    query.append('employeeIds', params.employeeId);
  }
  appendValue(query, 'employeeDeptId', params.employeeDeptId);
  appendValue(query, 'managerName', params.managerName);
  appendValue(query, 'statusCode', params.statusCode);
  appendValue(query, 'signOffStatus', params.signOffStatus);

  return query.toString();
}

function createTemplateQuery(params: Api.Performance.Template.SearchParams = {}) {
  const query = new URLSearchParams();

  query.append('pageNo', String(params.pageNo ?? 1));
  query.append('pageSize', String(params.pageSize ?? 10));
  appendValue(query, 'templateName', params.templateName);
  appendValue(query, 'employeeId', params.employeeId);
  appendValue(query, 'employeeName', params.employeeName);
  appendValue(query, 'templateYear', params.templateYear);
  appendValue(query, 'uploadUserName', params.uploadUserName);
  appendValue(query, 'activeFlag', params.activeFlag);

  return query.toString();
}

export async function fetchPerformanceTemplateCurrent(employeeId?: string | null) {
  const query = new URLSearchParams();
  appendValue(query, 'employeeId', employeeId);
  const result = await request<TemplateResponse | null>({
    ...safeJsonRequestConfig,
    url: query.toString() ? `${TEMPLATE_PREFIX}/current?${query.toString()}` : `${TEMPLATE_PREFIX}/current`,
    method: 'get'
  });

  return mapServiceResult(result as ServiceRequestResult<TemplateResponse | null>, data =>
    data ? normalizeTemplate(data) : null
  );
}

export async function fetchPerformanceTemplatePage(params: Api.Performance.Template.SearchParams = {}) {
  const query = createTemplateQuery(params);
  const result = await request<TemplatePageResponse>({
    ...safeJsonRequestConfig,
    url: query ? `${TEMPLATE_PREFIX}/page?${query}` : `${TEMPLATE_PREFIX}/page`,
    method: 'get'
  });

  return mapServiceResult(result as ServiceRequestResult<TemplatePageResponse>, data => ({
    total: normalizeTotal(data.total),
    list: data.list.map(normalizeTemplate)
  }));
}

export async function fetchPerformanceTemplateUploadScope() {
  const result = await request<TemplateUploadScopeResponse>({
    ...safeJsonRequestConfig,
    url: `${TEMPLATE_PREFIX}/upload-scope`,
    method: 'get'
  });

  return mapServiceResult(result as ServiceRequestResult<TemplateUploadScopeResponse>, normalizeTemplateUploadScope);
}

export async function uploadSinglePerformanceTemplate(data: Api.Performance.Template.SingleUploadParams) {
  const result = await request<StringIdResponse>({
    ...safeJsonRequestConfig,
    url: `${TEMPLATE_PREFIX}/upload-single`,
    method: 'post',
    data
  });

  return mapServiceResult(result as ServiceRequestResult<StringIdResponse>, normalizeStringId);
}

export async function batchImportPerformanceTemplates(data: Api.Performance.Template.BatchImportParams) {
  const result = await request<TemplateBatchImportResponse>({
    ...safeJsonRequestConfig,
    url: `${TEMPLATE_PREFIX}/batch-import`,
    method: 'post',
    data
  });

  return mapServiceResult(
    result as ServiceRequestResult<TemplateBatchImportResponse>,
    normalizeTemplateBatchImportResult
  );
}

export function activatePerformanceTemplate(id: string) {
  return request<boolean>({
    ...safeJsonRequestConfig,
    url: `${TEMPLATE_PREFIX}/${id}/activate`,
    method: 'post'
  });
}

export async function fetchPerformanceSheetPage(params: Api.Performance.Sheet.SearchParams = {}) {
  const query = createSheetQuery(params);
  const result = await request<SheetPageResponse>({
    ...safeJsonRequestConfig,
    url: query ? `${SHEET_PREFIX}/page?${query}` : `${SHEET_PREFIX}/page`,
    method: 'get'
  });

  return mapServiceResult(result as ServiceRequestResult<SheetPageResponse>, data => ({
    total: normalizeTotal(data.total),
    list: data.list.map(normalizeSheet)
  }));
}

export async function fetchPerformanceSheet(id: string) {
  const result = await request<SheetResponse>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/${id}`,
    method: 'get'
  });

  return mapServiceResult(result as ServiceRequestResult<SheetResponse>, normalizeSheet);
}

export async function createPerformanceSheet(data: Api.Performance.Sheet.CreateParams) {
  const result = await request<StringIdResponse>({
    ...safeJsonRequestConfig,
    url: SHEET_PREFIX,
    method: 'post',
    data
  });

  return mapServiceResult(result as ServiceRequestResult<StringIdResponse>, normalizeStringId);
}

export async function importPerformanceSheetZip(data: Api.Performance.Sheet.ImportZipParams) {
  const formData = new FormData();
  formData.append('file', data.file);
  formData.append('periodMonth', data.periodMonth);
  data.employeeIds?.forEach(id => {
    formData.append('employeeIds', id);
  });

  const result = await request<ImportZipResultResponse>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/import-zip`,
    method: 'post',
    data: formData
  });

  return mapServiceResult(result as ServiceRequestResult<ImportZipResultResponse>, payload => ({
    workbookCount: normalizeTotal(payload.workbookCount),
    sheetCount: normalizeTotal(payload.sheetCount),
    successCount: normalizeTotal(payload.successCount),
    skippedCount: normalizeTotal(payload.skippedCount),
    failedCount: normalizeTotal(payload.failedCount),
    messages: payload.messages ?? []
  }));
}

export async function signOffPerformanceSheets(data: Api.Performance.Sheet.SignOffParams) {
  const result = await request<StringIdResponse>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/sign-off`,
    method: 'post',
    data: {
      ...data,
      employeeIds: data.employeeIds && data.employeeIds.length ? data.employeeIds : undefined,
      remark: data.remark?.trim() || undefined
    }
  });

  return mapServiceResult(result as ServiceRequestResult<StringIdResponse>, normalizeStringId);
}

export function updatePerformanceSheetExcel(id: string, data: Api.Performance.Sheet.ExcelUpdateParams) {
  return request<boolean>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/${id}/excel`,
    method: 'put',
    data
  });
}

export function deletePerformanceSheet(id: string) {
  return request<boolean>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/${id}`,
    method: 'delete'
  });
}

export function sendPerformanceSheet(id: string) {
  return request<boolean>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/${id}/send`,
    method: 'post'
  });
}

export function resendPerformanceSheet(id: string) {
  return request<boolean>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/${id}/resend`,
    method: 'post'
  });
}

export function confirmPerformanceSheet(id: string, data: Api.Performance.Sheet.StatusActionParams = {}) {
  return request<boolean>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/${id}/confirm`,
    method: 'post',
    data
  });
}

export function rejectPerformanceSheet(id: string, data: Api.Performance.Sheet.StatusActionParams) {
  return request<boolean>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/${id}/reject`,
    method: 'post',
    data
  });
}

export function downloadPerformanceSheet(id: string) {
  return request<Blob, 'blob'>({
    url: `${SHEET_PREFIX}/${id}/download`,
    method: 'get',
    responseType: 'blob'
  });
}

export function batchDownloadPerformanceSheets(data: Api.Performance.Sheet.BatchDownloadParams) {
  return request<Blob, 'blob'>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/batch-download`,
    method: 'post',
    data,
    responseType: 'blob'
  });
}

export function exportPerformanceSheets(params: Api.Performance.Sheet.SearchParams = {}) {
  const query = createSheetQuery(params);

  return request<Blob, 'blob'>({
    url: query ? `${SHEET_PREFIX}/export?${query}` : `${SHEET_PREFIX}/export`,
    method: 'get',
    responseType: 'blob'
  });
}

export async function fetchPerformanceSheetStatusLogs(id: string) {
  const result = await request<StatusLogResponse[]>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/${id}/status-logs`,
    method: 'get'
  });

  return mapServiceResult(result as ServiceRequestResult<StatusLogResponse[]>, data => data.map(normalizeStatusLog));
}

export async function fetchPerformanceSheetResponseRecords(id: string) {
  const result = await request<ResponseRecordResponse[]>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/${id}/response-records`,
    method: 'get'
  });

  return mapServiceResult(result as ServiceRequestResult<ResponseRecordResponse[]>, data =>
    data.map(normalizeResponseRecord)
  );
}

export async function fetchPerformanceMonthlyResult(employeeId: string, periodMonth: string) {
  const result = await request<MonthlyResultResponse | null>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/monthly-result`,
    method: 'get',
    params: { employeeId, periodMonth }
  });

  return mapServiceResult(result as ServiceRequestResult<MonthlyResultResponse | null>, data =>
    data ? normalizeMonthlyResult(data) : null
  );
}

export async function fetchPerformanceSheetPrefill(employeeId: string, periodMonth: string) {
  const result = await request<PrefillResponse>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/prefill`,
    method: 'get',
    params: { employeeId, periodMonth }
  });

  return mapServiceResult(result as ServiceRequestResult<PrefillResponse>, normalizePrefillData);
}

export function fetchPerformanceSheetStatusDict() {
  return request<Api.Performance.Sheet.StatusDict[]>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/status-dict`,
    method: 'get'
  });
}

export function fetchPerformanceSheetStatusTransitions() {
  return request<Api.Performance.Sheet.StatusTransition[]>({
    ...safeJsonRequestConfig,
    url: `${SHEET_PREFIX}/status-transitions`,
    method: 'get'
  });
}

export async function fetchTeamPerformanceSummary(params: Api.Performance.Team.SummaryParams = {}) {
  const result = await request<TeamSummaryResponse>({
    ...safeJsonRequestConfig,
    url: `${TEAM_PREFIX}/summary`,
    method: 'get',
    params
  });

  return mapServiceResult(result as ServiceRequestResult<TeamSummaryResponse>, normalizeTeamSummary);
}

export function remindTeamPerformance(data: Api.Performance.Team.RemindParams) {
  return request<Api.Performance.Team.RemindResult>({
    ...safeJsonRequestConfig,
    url: `${TEAM_PREFIX}/remind`,
    method: 'post',
    data
  });
}
