import apiClient from "@/lib/api-client";

// 类型定义
export interface DingtalkTask {
  code: string;
  name: string;
  description: string;
  group: string;
  schedule: string;
  status: "ACTIVE" | "PAUSED" | "DISABLED";
  lastRunAt: string | null;
  lastStatus: "SUCCESS" | "FAILED" | "RUNNING" | null;
  totalRuns: number;
  successRuns: number;
  failedRuns: number;
}

export interface DingtalkOverview {
  totalTasks: number;
  registeredTasks: number;
  running: number;
  todaySuccess: number;
  todayFailed: number;
  isEnabled: boolean;
}

export interface DingtalkExecution {
  id: string;
  taskCode: string;
  taskName: string;
  status:
    | "PENDING"
    | "RUNNING"
    | "SUCCESS"
    | "FAILED"
    | "TIMEOUT"
    | "CANCELLED";
  startedAt: string;
  completedAt: string | null;
  duration: number | null;
  triggerType: string;
  error: string | null;
  result: DingtalkExecutionResult | null;
  logs: string | null;
}

export interface DingtalkExecutionResult {
  success?: boolean;
  processedCount?: number;
  errors?: string[];
  duration?: number;
  logs?: string;
  details?: { records?: DingtalkApprovalCancellationRecord[] };
}

export interface DingtalkConfig {
  enabled: boolean;
  tokenValid: boolean;
  appType: string;
  operatorId: string;
}

export interface TriggerResult {
  success: boolean;
  taskCode: string;
  taskName: string;
  processedCount: number;
  errors: string[];
  duration: number;
  logs?: string;
}

export interface DingtalkEmployee {
  userId: string;
  name: string;
}

export interface DingtalkApprovalCancellationParams {
  taskCode:
    | "DINGTALK_BUSINESS_TRIP"
    | "DINGTALK_FIELD_APPLICATION"
    | "DINGTALK_OVERTIME";
  userId: string;
  approveId: string;
  fromTime?: string;
  toTime?: string;
  dryRun?: boolean;
}

export interface DingtalkApprovalCancellationRecord {
  userId: string;
  approveId: string;
  creator: string;
  date: string | null;
  instanceIds: string[];
  serialNumbers: string[];
  taskCode:
    | "DINGTALK_BUSINESS_TRIP"
    | "DINGTALK_FIELD_APPLICATION"
    | "DINGTALK_OVERTIME";
  status?: "CANCELLED" | "FAILED" | "ERROR";
  response?: Record<string, unknown>;
  error?: string;
}

export interface DingtalkAnnualLeaveQuotaItem {
  userId: string;
  name: string;
  employeeNumber: string;
  status: string;
  leaveType: string;
  leaveCode: string;
  quotaCycle: string;
  totalDays: number;
  usedDays: number;
  remainingDays: number;
  startTime: string | null;
  endTime: string | null;
  releasedDays?: number;
  usedFromRecords?: number;
  localPlanTotalDays?: number | null;
  localPlanNotCountDays?: number | null;
  localPlanReleasedByToday?: number | null;
}

export interface DingtalkEmployeeStatusInfo {
  userId: string;
  periodCount: number;
  hasActiveSuspension: boolean;
  hasAnySuspension: boolean;
}

export interface DingtalkLeaveTypeInfo {
  leaveCode: string;
  leaveType: string;
  hasQuota: boolean;
}

export interface DingtalkAnnualLeaveQuotaResponse {
  lastSyncedAt: string | null;
  summary: {
    employeeCount: number;
    leaveTypeCount: number;
    nonZeroQuotaCount: number;
  };
  allLeaveTypes?: DingtalkLeaveTypeInfo[];
  allEmployees?: { userId: string; name: string; employeeNumber: string }[];
  employeeStatuses?: DingtalkEmployeeStatusInfo[];
  items: DingtalkAnnualLeaveQuotaItem[];
}

export interface DingtalkAnnualLeaveQuotaRefreshResponse {
  employeeCount: number;
  recordCount: number;
  leaveTypeCount: number;
  lastSyncedAt: string;
}

export interface DingtalkAnnualLeaveUsageRecord {
  date: string | null;
  startTime: string | null;
  endTime: string | null;
  days: number;
  status: string;
  recordType: string;
}

export interface DingtalkAnnualLeaveReleaseRecord {
  date: string | null;       // 操作日期（gmtCreate）
  startDate?: string | null; // 有效期开始
  endDate?: string | null;   // 有效期结束
  days: number;              // 变更天数（正=释放，负=撤销）
  released: boolean;
  reason?: string;           // 备注（如"系统自动释放年假"）
  calType?: string;          // insert/add/delete/update
  opUserId?: string | null;  // 操作人
}

export interface DingtalkAnnualLeaveQuotaDetail {
  userId: string;
  name: string;
  employeeNumber: string;
  leaveType: string;
  leaveCode: string;
  quotaCycle: string;
  totalDays: number;
  usedDays: number;
  remainingDays: number;
  startTime: string | null;
  endTime: string | null;
  usageRecords: DingtalkAnnualLeaveUsageRecord[];
  releaseRecords: DingtalkAnnualLeaveReleaseRecord[];
  localPlanTotalDays?: number | null;
  localPlanNotCountDays?: number | null;
  localPlanAdjustmentDays?: number | null;
  localPlanReleasedByToday?: number | null;
  tenureDays?: number;
  workStartDate?: string | null;
  employmentPeriods?: Array<{
    periodIndex: number;
    joinDate: string;
    leaveDate: string | null;
    countInTenure: boolean;
    note: string;
  }>;
  suspensionPeriods?: Array<{
    startDate: string;
    endDate: string | null;
    reason: string;
    note: string;
  }>;
}

export interface DingtalkAnnualLeaveReleasePlanItem {
  date: string;
  userId: string;
  name: string;
  employeeNumber: string;
  status: string;
  days: number;
  released: boolean;
  year: string;
  hasPlan: boolean;
  noPlanReason?: string | null;
}

export interface DingtalkAnnualLeaveReleasePlanResponse {
  summary: {
    employeeCount: number;
    planCount: number;
    upcomingDays: number;
    todayReleaseEmployeeCount: number;
  };
  items: DingtalkAnnualLeaveReleasePlanItem[];
}

export interface DingtalkAnnualLeaveReleasePlanRefreshResponse {
  success?: boolean;
  processedCount?: number;
  errors?: string[];
  duration?: number;
  logs?: string;
}

export interface DingtalkAnnualLeaveReleaseResponse {
  success?: boolean;
  processedCount?: number;
  errors?: string[];
  duration?: number;
  logs?: string;
}

export interface DingtalkAnnualLeavePlanSettings {
  userId: string;
  year: number;
  adjustmentDays: number;
  notCountDays: number;
  totalDays: number;
  releaseSchedule: Array<{
    dayIndex: number;
    releaseDate: string;
  }>;
  lastCalculatedAt: string | null;
}

// API 函数
// 注意: apiClient 拦截器已自动解包 response.data.data，直接返回即可

export async function getDingtalkEmployees(): Promise<DingtalkEmployee[]> {
  return apiClient.get("/organization/dingtalk/employees");
}

export async function getDingtalkOverview(): Promise<DingtalkOverview> {
  return apiClient.get("/organization/dingtalk/overview");
}

export async function getDingtalkTasks(): Promise<DingtalkTask[]> {
  return apiClient.get("/organization/dingtalk/tasks");
}

export async function triggerDingtalkTask(
  code: string,
  params?: { fromTime?: string; toTime?: string; userId?: string },
): Promise<TriggerResult> {
  return apiClient.post(
    `/organization/dingtalk/tasks/${code}/trigger`,
    params || {},
  );
}

export function triggerDingtalkTaskStream(
  code: string,
  params?: { fromTime?: string; toTime?: string; userId?: string },
  onLog?: (entry: { time: string; level: string; message: string }) => void,
  onDone?: (result: TriggerResult) => void,
  onError?: (error: string) => void,
): AbortController {
  const abort = new AbortController();
  const qs = new URLSearchParams();
  if (params?.fromTime) qs.set("fromTime", params.fromTime);
  if (params?.toTime) qs.set("toTime", params.toTime);
  if (params?.userId) qs.set("userId", params.userId.trim());

  const url = `/api/v1/organization/dingtalk/tasks/${code}/trigger-stream?${qs.toString()}`;

  const token =
    typeof window !== "undefined" ? localStorage.getItem("token") : null;
  fetch(url, {
    signal: abort.signal,
    credentials: "include",
    headers: token ? { Authorization: `Bearer ${token}` } : {},
  })
    .then(async (response) => {
      const reader = response.body?.getReader();
      if (!reader) return;
      const decoder = new TextDecoder();
      let buffer = "";

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        buffer += decoder.decode(value, { stream: true });

        const lines = buffer.split("\n");
        buffer = lines.pop() || "";

        for (const line of lines) {
          if (!line.startsWith("data: ")) continue;
          try {
            const data = JSON.parse(line.slice(6));
            if (data.type === "log") onLog?.(data);
            else if (data.type === "done") onDone?.(data);
            else if (data.type === "error") onError?.(data.message);
          } catch {}
        }
      }
    })
    .catch((err) => {
      if (err.name !== "AbortError") onError?.(err.message);
    });

  return abort;
}

export async function getTaskExecutions(
  code: string,
  params?: { page?: number; limit?: number },
): Promise<{
  items: DingtalkExecution[];
  total: number;
  page: number;
  limit: number;
}> {
  return apiClient.get(`/organization/dingtalk/tasks/${code}/executions`, {
    params,
  });
}

export interface ExecutionQueryParams {
  page?: number;
  limit?: number;
  taskCode?: string;
  startDate?: string;
  endDate?: string;
  hideEmpty?: boolean;
}

export interface PaginatedExecutions {
  items: DingtalkExecution[];
  total: number;
  page: number;
  limit: number;
}

export async function getRecentExecutions(
  params: ExecutionQueryParams = {},
): Promise<PaginatedExecutions> {
  return apiClient.get("/organization/dingtalk/executions/recent", {
    params: {
      page: params.page || 1,
      limit: params.limit || 20,
      ...(params.taskCode && { taskCode: params.taskCode }),
      ...(params.startDate && { startDate: params.startDate }),
      ...(params.endDate && { endDate: params.endDate }),
      ...(params.hideEmpty && { hideEmpty: 'true' }),
    },
  });
}

export async function getDingtalkConfig(): Promise<DingtalkConfig> {
  return apiClient.get("/organization/dingtalk/config");
}

export async function updateDingtalkConfig(data: {
  enabled?: boolean;
}): Promise<{ success: boolean; enabled: boolean }> {
  return apiClient.patch("/organization/dingtalk/config", data);
}

export async function updateDingtalkTask(
  code: string,
  data: { status?: string },
): Promise<{ success: boolean; task: DingtalkTask }> {
  return apiClient.patch(`/organization/dingtalk/tasks/${code}`, data);
}

export async function cancelDingtalkApprovals(
  data: DingtalkApprovalCancellationParams,
): Promise<
  TriggerResult & {
    details?: { records?: DingtalkApprovalCancellationRecord[] };
  }
> {
  return apiClient.post("/organization/dingtalk/approval-cancellations", data);
}

export async function getDingtalkLeaveRecords(params: {
  userId: string;
  leaveCode: string;
}): Promise<{ records: unknown[] }> {
  return apiClient.get("/organization/dingtalk/annual-leave/records", {
    params,
  });
}

export async function getDingtalkAnnualLeaveDetail(params: {
  userId: string;
  leaveCode: string;
}): Promise<DingtalkAnnualLeaveQuotaDetail | null> {
  return apiClient.get("/organization/dingtalk/annual-leave/details", {
    params,
  });
}

export async function getDingtalkAnnualLeaveQuotas(params?: {
  userId?: string;
  keyword?: string;
  hideZero?: boolean;
  includeAllStatuses?: boolean;
}): Promise<DingtalkAnnualLeaveQuotaResponse> {
  return apiClient.get("/organization/dingtalk/annual-leave/quotas", {
    params,
  });
}

export async function refreshDingtalkAnnualLeaveQuotas(data?: {
  userId?: string;
}): Promise<DingtalkAnnualLeaveQuotaRefreshResponse> {
  return apiClient.post(
    "/organization/dingtalk/annual-leave/quotas/refresh",
    data || {},
  );
}

export async function getDingtalkAnnualLeaveReleasePlan(params?: {
  year?: number;
  userId?: string;
  keyword?: string;
  upcomingOnly?: boolean;
}): Promise<DingtalkAnnualLeaveReleasePlanResponse> {
  return apiClient.get("/organization/dingtalk/annual-leave/release-plan", {
    params,
  });
}

export async function exportDingtalkAnnualLeaveReleasePlan(params?: {
  year?: number;
  keyword?: string;
  upcomingOnly?: boolean;
}): Promise<void> {
  const searchParams = new URLSearchParams();
  if (params?.year) searchParams.set("year", String(params.year));
  if (params?.keyword) searchParams.set("keyword", params.keyword);
  if (params?.upcomingOnly !== undefined) searchParams.set("upcomingOnly", String(params.upcomingOnly));
  const qs = searchParams.toString();
  const url = `/api/v1/organization/dingtalk/annual-leave/release-plan/export${qs ? `?${qs}` : ""}`;
  const token = typeof window !== "undefined" ? localStorage.getItem("token") : null;
  const resp = await fetch(url, {
    headers: token ? { Authorization: `Bearer ${token}` } : {},
  });
  if (!resp.ok) throw new Error(`导出失败: ${resp.status}`);
  const blob = await resp.blob();
  const disposition = resp.headers.get("Content-Disposition") || "";
  const filenameMatch = disposition.match(/filename="?([^"]+)"?/);
  const filename = filenameMatch?.[1] || `annual-leave-release-plan-${params?.year || new Date().getFullYear()}.csv`;
  const a = document.createElement("a");
  a.href = URL.createObjectURL(blob);
  a.download = filename;
  a.click();
  URL.revokeObjectURL(a.href);
}

export async function refreshDingtalkAnnualLeaveReleasePlan(data?: {
  userId?: string;
  year?: number;
}): Promise<DingtalkAnnualLeaveReleasePlanRefreshResponse> {
  return apiClient.post(
    "/organization/dingtalk/annual-leave/release-plan/refresh",
    data || {},
  );
}

export async function triggerDingtalkAnnualLeaveRelease(data?: {
  userId?: string;
  year?: number;
}): Promise<DingtalkAnnualLeaveReleaseResponse> {
  return apiClient.post(
    "/organization/dingtalk/annual-leave/release",
    data || {},
  );
}

export async function getDingtalkAnnualLeavePlanSettings(params: {
  userId: string;
  year?: number;
}): Promise<DingtalkAnnualLeavePlanSettings> {
  return apiClient.get("/organization/dingtalk/annual-leave/plan-settings", {
    params,
  });
}

export async function updateDingtalkAnnualLeavePlanSettings(data: {
  userId: string;
  year: number;
  adjustmentDays?: number;
  notCountDays?: number;
  recalculate?: boolean;
}): Promise<DingtalkAnnualLeavePlanSettings> {
  return apiClient.patch("/organization/dingtalk/annual-leave/plan-settings", data);
}

// ========== 年假额度手动调整 ==========

export async function updateAnnualLeaveQuota(data: {
  userId: string;
  year: number;
  totalDays: number;
}): Promise<{
  success: boolean;
  error?: string;
  detail?: { name: string; userId: string; year: number; oldDays: number; newDays: number };
}> {
  return apiClient.patch("/organization/dingtalk/annual-leave/quota", data);
}

// ========== 钉钉员工管理 ==========

export interface DingtalkEmployeeItem {
  userId: string;
  name: string;
  employeeNumber: string;
  department: string;
  position: string;
  rank: string;
  phone: string;
  country: string;
  workPlace: string;
  contractCompany: string;
  bank: string;
  bankCardLast4: string;
  monthlyStandardHours: string;
  workHourLimit: string;
  joinDate: string | null;
  workStartDate: string | null;
  tenureDays: number;
  status: string;
  adjustmentDays: number;
  notCountDays: number;
  lastSyncedAt: string | null;
}

export interface DingtalkEmployeeListResponse {
  items: DingtalkEmployeeItem[];
  total: number;
  page: number;
  pageSize: number;
}

export interface DingtalkEmployeeUpdateResponse {
  success: boolean;
  employee: DingtalkEmployeeItem;
}

export async function getDingtalkEmployeeList(params?: {
  keyword?: string;
  status?: string;
  page?: number;
  pageSize?: number;
}): Promise<DingtalkEmployeeListResponse> {
  return apiClient.get("/organization/dingtalk/employees/list", { params });
}

export async function updateDingtalkEmployee(
  userId: string,
  data: { status?: string; adjustmentDays?: number; notCountDays?: number },
): Promise<DingtalkEmployeeUpdateResponse> {
  return apiClient.put(`/organization/dingtalk/employees/${userId}`, data);
}

export async function syncDingtalkEmployees(): Promise<{
  total: number;
  created: number;
  updated: number;
  terminated: number;
}> {
  return apiClient.post("/organization/dingtalk/employees/sync");
}

// ==================== 员工在职周期（离职再入职）====================

export interface EmploymentPeriod {
  id: string;
  userId: string;
  periodIndex: number;
  joinDate: string;           // ISO date
  leaveDate: string | null;
  countInTenure: boolean;
  note: string;
}

export interface TenureDetail {
  totalDays: number;
  source: "periods" | "joinDate";
  periods: Array<{
    joinDate: string;
    leaveDate: string | null;
    days: number;
    countInTenure: boolean;
    note: string;
  }>;
}

export async function getEmploymentPeriods(userId: string): Promise<EmploymentPeriod[]> {
  return apiClient.get(`/organization/dingtalk/employees/${userId}/employment-periods`);
}

export async function addEmploymentPeriod(
  userId: string,
  data: { joinDate: string; leaveDate?: string | null; countInTenure?: boolean; note?: string },
): Promise<EmploymentPeriod> {
  return apiClient.post(`/organization/dingtalk/employees/${userId}/employment-periods`, data);
}

export async function updateEmploymentPeriod(
  userId: string,
  id: string,
  data: { joinDate?: string; leaveDate?: string | null; countInTenure?: boolean; note?: string },
): Promise<EmploymentPeriod> {
  return apiClient.put(`/organization/dingtalk/employees/${userId}/employment-periods/${id}`, data);
}

export async function deleteEmploymentPeriod(userId: string, id: string): Promise<void> {
  return apiClient.delete(`/organization/dingtalk/employees/${userId}/employment-periods/${id}`);
}

export async function getEmployeeTenure(userId: string): Promise<TenureDetail> {
  return apiClient.get(`/organization/dingtalk/employees/${userId}/tenure`);
}

export interface SuspensionPeriod {
  id: string;
  userId: string;
  startDate: string;
  endDate: string | null;
  reason: string;
  note: string;
}

export async function getSuspensionPeriods(userId: string): Promise<SuspensionPeriod[]> {
  return apiClient.get(`/organization/dingtalk/employees/${userId}/suspension-periods`);
}

export async function addSuspensionPeriod(
  userId: string,
  data: { startDate: string; endDate?: string | null; reason?: string; note?: string },
): Promise<SuspensionPeriod> {
  return apiClient.post(`/organization/dingtalk/employees/${userId}/suspension-periods`, data);
}

export async function updateSuspensionPeriod(
  userId: string,
  id: string,
  data: { startDate?: string; endDate?: string | null; reason?: string; note?: string },
): Promise<SuspensionPeriod> {
  return apiClient.put(`/organization/dingtalk/employees/${userId}/suspension-periods/${id}`, data);
}

export async function deleteSuspensionPeriod(userId: string, id: string): Promise<void> {
  return apiClient.delete(`/organization/dingtalk/employees/${userId}/suspension-periods/${id}`);
}

// ==================== SAP 采购同步 ====================

export interface SapPurchaseItem {
  formInstanceId: string;
  serialNumber: string;
  applicantName: string;
  applicantDept: string;
  applicantEmployeeId: string;
  budgetNumber: string;
  budgetAmount: number;
  purchaseProjectDescription: string;
  applicationDate: string;
  demandCategory: string;
  demandInitiator: string;
  companyName: string;
  purchasingCompanyName: string;
  purchaser: string;
  expectedCompletionDate: string;
  materialGroup: string;
  costCenterNumber: string;
  fixedAssetsNumber: string;
  generalLedgerAccount: string;
  syncStatus: "NOT_SYNCED" | "SUCCESS" | "EXISTS" | "FAILED";
  sapPrNumber: string | null;
  sapMessages: Array<{ type: string; message: string }> | null;
  sapRawResponse: Record<string, any> | null;
  approverChain: string | null;
  syncedAt: string | null;
  sapRequestPreview: {
    header: Record<string, string>;
    item: Record<string, string | number>;
  } | null;
}

export interface SapPurchaseListResponse {
  items: SapPurchaseItem[];
  total: number;
}

export interface SapSyncRecord {
  id: string;
  serialNumber: string;
  formInstanceId: string;
  applicantName: string;
  budgetAmount: number;
  sapPrNumber: string | null;
  sapStatus: string;
  sapMessages: Array<{ type: string; message: string }> | null;
  approverChain: string | null;
  syncedAt: string;
  createdAt: string;
}

export interface SapSyncBatchResult {
  success: boolean;
  total: number;
  successCount: number;
  failedCount: number;
  results: Array<{
    serialNumber: string;
    success: boolean;
    prNumber: string | null;
    messages: Array<{ type: string; message: string }>;
    approverChain: string;
  }>;
}

export async function getSapPurchaseList(params: {
  sapEnv?: "test" | "production";
  keyword?: string;
  status?: string;
}): Promise<SapPurchaseListResponse> {
  return apiClient.get("/organization/dingtalk/sap-purchases/list", { params });
}

export async function refreshSapPurchaseCache(sapEnv: "test" | "production" = "production"): Promise<{
  fetched: number;
  upserted: number;
  fromTime: string;
  toTime: string;
}> {
  return apiClient.post("/organization/dingtalk/sap-purchases/refresh", { sapEnv });
}

export async function getSapPurchaseRecords(params: {
  page?: number;
  limit?: number;
  status?: string;
}): Promise<{ items: SapSyncRecord[]; total: number; page: number; limit: number; totalPages: number }> {
  return apiClient.get("/organization/dingtalk/sap-purchases/records", { params });
}

export async function syncSapPurchases(body: {
  serialNumbers: string[];
  sapEnv: "test" | "production";
}): Promise<SapSyncBatchResult> {
  return apiClient.post("/organization/dingtalk/sap-purchases/sync", body);
}
