import { WEB_SERVICE_PREFIX } from '@/constants/service';
import { request } from '../request';
import { type ProjectLocalDateValue, normalizeProjectLocalDate } from './project-shared';
import { type ServiceRequestResult, mapServiceResult, normalizeStringId, safeJsonRequestConfig } from './shared';

const OVERTIME_APPLICATION_PREFIX = `${WEB_SERVICE_PREFIX}/project/overtime-applications`;

type StringIdResponse = string | number;

type OvertimeApplicationResponse = Omit<
  Api.OvertimeApplication.OvertimeApplication,
  'id' | 'applicantId' | 'approverId' | 'overtimeDate' | 'allowEdit' | 'terminal'
> & {
  id: StringIdResponse;
  applicantId: StringIdResponse;
  approverId: StringIdResponse;
  overtimeDate: ProjectLocalDateValue;
  allowEdit?: boolean | number | string | null;
  terminal?: boolean | number | string | null;
};

type OvertimeApplicationPageResponse = Omit<Api.OvertimeApplication.OvertimeApplicationPageResult, 'total' | 'list'> & {
  total: number | string;
  list: OvertimeApplicationResponse[];
};

type OvertimeApplicationApprovalRecordResponse = Omit<
  Api.OvertimeApplication.OvertimeApplicationApprovalRecord,
  'id' | 'overtimeApplicationId' | 'statusLogId' | 'auditorUserId'
> & {
  id: StringIdResponse;
  overtimeApplicationId: StringIdResponse;
  statusLogId: StringIdResponse;
  auditorUserId: StringIdResponse;
};

type TeamOvertimeSummaryResponse = Omit<
  Api.OvertimeApplication.TeamOvertimeSummary,
  'overtimeDateStart' | 'overtimeDateEnd'
> & {
  overtimeDateStart?: unknown;
  overtimeDateEnd?: unknown;
};

function normalizeDateText(value: unknown) {
  if (value === null || value === undefined) return undefined;
  const text = String(value).trim();
  const commaDateMatch = text.match(/^(\d{4}),(\d{1,2}),(\d{1,2})$/);

  if (commaDateMatch) {
    const [, year, month, day] = commaDateMatch;
    return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
  }

  return text || undefined;
}

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(total: number | string) {
  const value = Number(total);

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

function normalizeOvertimeApplication(
  response: OvertimeApplicationResponse
): Api.OvertimeApplication.OvertimeApplication {
  return {
    ...response,
    id: normalizeStringId(response.id),
    applicantId: normalizeStringId(response.applicantId),
    approverId: normalizeStringId(response.approverId),
    overtimeDate: normalizeProjectLocalDate(response.overtimeDate) ?? '',
    statusName: response.statusName || response.statusCode,
    allowEdit: normalizeBooleanFlag(response.allowEdit),
    terminal: normalizeBooleanFlag(response.terminal),
    approvalComment: response.approvalComment ?? null,
    approvalTime: response.approvalTime ?? null
  };
}

function normalizeApprovalRecord(
  response: OvertimeApplicationApprovalRecordResponse
): Api.OvertimeApplication.OvertimeApplicationApprovalRecord {
  return {
    ...response,
    id: normalizeStringId(response.id),
    overtimeApplicationId: normalizeStringId(response.overtimeApplicationId),
    statusLogId: normalizeStringId(response.statusLogId),
    auditorUserId: normalizeStringId(response.auditorUserId),
    opinion: response.opinion ?? null
  };
}

function createPageQuery(params: Api.OvertimeApplication.OvertimeApplicationSearchParams = {}) {
  const query = new URLSearchParams();

  query.append('pageNo', String(params.pageNo ?? 1));
  query.append('pageSize', String(params.pageSize ?? 10));

  if (params.applicantIds !== null && params.applicantIds !== undefined) {
    if (params.applicantIds.length) {
      params.applicantIds.forEach(item => {
        if (item) {
          query.append('applicantIds', item);
        }
      });
    } else {
      query.append('applicantIds', '');
    }
  }

  if (params.keyword) {
    query.append('keyword', params.keyword);
  }

  if (params.applicantName) {
    query.append('applicantName', params.applicantName);
  }

  if (params.approverId) {
    query.append('approverId', params.approverId);
  }

  if (params.approverName) {
    query.append('approverName', params.approverName);
  }

  if (params.statusCode) {
    query.append('statusCode', params.statusCode);
  }

  params.overtimeDate?.forEach(item => {
    if (item) {
      query.append('overtimeDate', item);
    }
  });

  params.createTime?.forEach(item => {
    if (item) {
      query.append('createTime', item);
    }
  });

  return query.toString();
}

function toSaveRequest(data: Api.OvertimeApplication.SaveOvertimeApplicationParams) {
  return {
    overtimeDate: data.overtimeDate,
    overtimeDuration: data.overtimeDuration,
    overtimeReason: data.overtimeReason.trim(),
    overtimeContent: data.overtimeContent.trim(),
    approverId: data.approverId
  };
}

function toStatusActionRequest(data: Api.OvertimeApplication.StatusActionParams = {}) {
  return {
    reason: data.reason?.trim() || undefined
  };
}

export async function fetchGetOvertimeApplicationPage(
  params: Api.OvertimeApplication.OvertimeApplicationSearchParams = {}
) {
  const query = createPageQuery(params);

  const result = await request<OvertimeApplicationPageResponse>({
    ...safeJsonRequestConfig,
    url: query ? `${OVERTIME_APPLICATION_PREFIX}/page?${query}` : `${OVERTIME_APPLICATION_PREFIX}/page`,
    method: 'get'
  });

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

export async function fetchGetOvertimeApplicationApprovalPage(
  params: Api.OvertimeApplication.OvertimeApplicationSearchParams = {}
) {
  const query = createPageQuery(params);

  const result = await request<OvertimeApplicationPageResponse>({
    ...safeJsonRequestConfig,
    url: query
      ? `${OVERTIME_APPLICATION_PREFIX}/approval-page?${query}`
      : `${OVERTIME_APPLICATION_PREFIX}/approval-page`,
    method: 'get'
  });

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

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

  return mapServiceResult(result as ServiceRequestResult<OvertimeApplicationResponse>, normalizeOvertimeApplication);
}

export async function fetchCreateOvertimeApplication(data: Api.OvertimeApplication.SaveOvertimeApplicationParams) {
  const result = await request<string | number>({
    ...safeJsonRequestConfig,
    url: OVERTIME_APPLICATION_PREFIX,
    method: 'post',
    data: toSaveRequest(data)
  });

  return mapServiceResult(result as ServiceRequestResult<string | number>, normalizeStringId);
}

export function fetchUpdateRejectedOvertimeApplication(
  id: string,
  data: Api.OvertimeApplication.SaveOvertimeApplicationParams
) {
  return request<boolean>({
    ...safeJsonRequestConfig,
    url: `${OVERTIME_APPLICATION_PREFIX}/${id}`,
    method: 'put',
    data: toSaveRequest(data)
  });
}

export function fetchApproveOvertimeApplication(id: string, data: Api.OvertimeApplication.StatusActionParams = {}) {
  return request<boolean>({
    ...safeJsonRequestConfig,
    url: `${OVERTIME_APPLICATION_PREFIX}/${id}/approve`,
    method: 'post',
    data: toStatusActionRequest(data)
  });
}

export function fetchRejectOvertimeApplication(id: string, data: Api.OvertimeApplication.StatusActionParams) {
  return request<boolean>({
    ...safeJsonRequestConfig,
    url: `${OVERTIME_APPLICATION_PREFIX}/${id}/reject`,
    method: 'post',
    data: toStatusActionRequest(data)
  });
}

export function fetchBatchApproveOvertimeApplication(
  data: Api.OvertimeApplication.OvertimeApplicationBatchActionParams
) {
  return request<Api.OvertimeApplication.OvertimeApplicationBatchActionResult>({
    ...safeJsonRequestConfig,
    url: `${OVERTIME_APPLICATION_PREFIX}/batch-approve`,
    method: 'post',
    data
  });
}

export function fetchBatchRejectOvertimeApplication(
  data: Api.OvertimeApplication.OvertimeApplicationBatchActionParams
) {
  return request<Api.OvertimeApplication.OvertimeApplicationBatchActionResult>({
    ...safeJsonRequestConfig,
    url: `${OVERTIME_APPLICATION_PREFIX}/batch-reject`,
    method: 'post',
    data
  });
}

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

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

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

export async function fetchGetOvertimeApplicationStatusDict() {
  const result = await request<Api.OvertimeApplication.OvertimeApplicationStatusDict[]>({
    ...safeJsonRequestConfig,
    url: `${OVERTIME_APPLICATION_PREFIX}/status/dict`,
    method: 'get'
  });

  return mapServiceResult(
    result as ServiceRequestResult<Api.OvertimeApplication.OvertimeApplicationStatusDict[]>,
    data => data
  );
}

export async function fetchGetTeamOvertimeSummary(params: Api.OvertimeApplication.TeamOvertimeSummaryParams = {}) {
  const result = await request<TeamOvertimeSummaryResponse>({
    ...safeJsonRequestConfig,
    url: `${OVERTIME_APPLICATION_PREFIX}/team/summary`,
    method: 'get',
    params
  });

  return mapServiceResult(result as ServiceRequestResult<TeamOvertimeSummaryResponse>, data => {
    if (!data) return data;
    return {
      ...data,
      overtimeDateStart: normalizeDateText(data.overtimeDateStart) || '',
      overtimeDateEnd: normalizeDateText(data.overtimeDateEnd) || ''
    };
  });
}

export function fetchExportOvertimeApplications(params: Api.OvertimeApplication.OvertimeApplicationSearchParams = {}) {
  const query = createPageQuery(params);

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