import { fetchAllCursorPages } from "../../../common/core/pagination";
import apiClient from "./apiClient";
import { userManager } from "./auth";

export type AuditLog = {
  event_id: string;
  timestamp: string;
  user_id: string;
  event_type: string;
  status: string;
  ip_address: string;
  user_agent: string;
  device_id?: string;
  details?: string;
};

export type AuditLogListResponse = {
  items: AuditLog[];
  limit: number;
  cursor?: string;
  next_cursor?: string;
};

export type TenantSummary = {
  id: string;
  type: string; // 허용 타입: PERSONAL, COMPANY, COMPANY_GROUP, ORGANIZATION, USER_GROUP
  name: string;
  slug: string;
  description: string;
  status: string;
  domains?: string[];
  parentId?: string;
  config?: Record<string, unknown>;
  memberCount: number; // 해당 테넌트 직접 소속 인원
  totalMemberCount?: number; // 하위 테넌트 포함 전체 인원
  createdAt: string;
  updatedAt: string;
};

export type TenantCreateRequest = {
  name: string;
  type?: string;
  slug?: string;
  parentId?: string;
  description?: string;
  status?: string;
  domains?: string[];
  forceDomainConflicts?: string[];
  config?: Record<string, unknown>;
};

export type TenantListResponse = {
  items: TenantSummary[];
  limit: number;
  offset: number;
  total: number;
  cursor?: string;
  nextCursor?: string;
  next_cursor?: string;
};

export type TenantUpdateRequest = {
  name?: string;
  type?: string;
  slug?: string;
  parentId?: string;
  description?: string;
  status?: string;
  domains?: string[];
  forceDomainConflicts?: string[];
  config?: Record<string, unknown>;
};

export type TenantImportDetail = {
  row: number;
  slug: string;
  name: string;
  success: boolean;
  action: "created" | "updated" | "failed" | "skipped";
  message: string;
  modifiedFields?: string[];
};

export type TenantImportResult = {
  created: number;
  updated: number;
  failed: number;
  errors: string[];
  details: TenantImportDetail[];
};

export type ApiKeySummary = {
  id: string;
  name: string;
  client_id: string;
  scopes: string[];
  status: string;
  lastUsedAt?: string;
  createdAt: string;
};

export type ApiKeyListResponse = {
  items: ApiKeySummary[];
  total: number;
};

export type RoleSummary = {
  id: string;
  name: string;
  description: string;
  permissions: string[];
  createdAt: string;
  updatedAt: string;
};

export type RoleListResponse = {
  items: RoleSummary[];
  total: number;
};

export type RPUsageDailyMetric = {
  date: string;
  tenantId: string;
  tenantType: string;
  tenantName?: string;
  clientId: string;
  clientName: string;
  loginRequests: number;
  otherRequests: number;
  uniqueSubjects: number;
};

export type RPUsagePeriod = "day" | "week" | "month";

export type RPUsageDailyResponse = {
  items: RPUsageDailyMetric[];
  days: number;
  period: RPUsagePeriod;
  tenantId?: string;
};

export type AdminOverviewStats = {
  totalTenants: number;
  totalUsers: number;
  oidcClients: number;
  auditEvents24h: number;
};

export type UserProjectionStatus = {
  name: string;
  status: "ready" | "failed" | "syncing" | string;
  ready: boolean;
  lastSyncedAt?: string;
  lastError?: string;
  updatedAt?: string;
  projectedUsers: number;
};

export type IdentityCacheStatus = {
  status: string;
  redisReady: boolean;
  observedCount: number;
  keyCount: number;
  lastRefreshedAt?: string;
  lastError?: string;
  updatedAt?: string;
};

export type OrySSOTSystemStatus = {
  userProjection: UserProjectionStatus;
  identityCache: IdentityCacheStatus;
};

export type IdentityCacheFlushResult = {
  status: string;
  flushedKeys: number;
  updatedAt: string;
};

export type DataIntegrityStatus = "pass" | "warning" | "fail";

export type DataIntegrityCheck = {
  key: string;
  label: string;
  description: string;
  status: DataIntegrityStatus;
  severity: "info" | "warning" | "error" | string;
  count: number;
};

export type DataIntegritySection = {
  key: string;
  label: string;
  status: DataIntegrityStatus;
  checks: DataIntegrityCheck[];
};

export type DataIntegrityReport = {
  status: DataIntegrityStatus;
  checkedAt: string;
  summary: {
    totalChecks: number;
    passed: number;
    warnings: number;
    failures: number;
  };
  sections: DataIntegritySection[];
};

export type OrphanUserLoginID = {
  id: string;
  userId: string;
  userEmail?: string;
  userDeletedAt?: string;
  tenantId: string;
  tenantSlug?: string;
  tenantDeletedAt?: string;
  fieldKey: string;
  loginId: string;
  reasons: string[];
};

export type OrphanUserLoginIDListResponse = {
  items: OrphanUserLoginID[];
  total: number;
};

export type DeleteOrphanUserLoginIDsResult = {
  deletedCount: number;
  deleted: OrphanUserLoginID[];
  skippedIds: string[];
};

export async function fetchAuditLogs(
  limit = 50,
  cursor?: string,
  search?: string,
  status?: string,
) {
  const { data } = await apiClient.get<AuditLogListResponse>("/v1/audit", {
    params: { limit, cursor, search, status },
  });
  return data;
}

export async function fetchAdminOverviewStats() {
  const { data } = await apiClient.get<AdminOverviewStats>("/v1/admin/stats");
  return data;
}

export async function fetchDataIntegrityReport() {
  const { data } = await apiClient.get<DataIntegrityReport>(
    "/v1/admin/integrity",
  );
  return data;
}

export async function fetchOrphanUserLoginIDs() {
  const { data } = await apiClient.get<OrphanUserLoginIDListResponse>(
    "/v1/admin/integrity/orphan-user-login-ids",
  );
  return data;
}

export async function deleteOrphanUserLoginIDs(ids: string[]) {
  const { data } = await apiClient.delete<DeleteOrphanUserLoginIDsResult>(
    "/v1/admin/integrity/orphan-user-login-ids",
    { data: { ids } },
  );
  return data;
}

export async function fetchUserProjectionStatus() {
  const { data } = await apiClient.get<UserProjectionStatus>(
    "/v1/admin/projections/users",
  );
  return data;
}

export async function fetchOrySSOTSystemStatus() {
  const { data } =
    await apiClient.get<OrySSOTSystemStatus>("/v1/admin/ory/ssot");
  return data;
}

export async function flushIdentityCache() {
  const { data } = await apiClient.post<IdentityCacheFlushResult>(
    "/v1/admin/ory/ssot/identity-cache/flush",
  );
  return data;
}

export async function fetchAdminRPUsageDaily({
  days = 14,
  period = "day",
  tenantId,
}: {
  days?: number;
  period?: RPUsagePeriod;
  tenantId?: string;
} = {}) {
  const { data } = await apiClient.get<RPUsageDailyResponse>(
    "/v1/admin/rp-usage/daily",
    {
      params: { days, period, tenantId: tenantId || undefined },
    },
  );
  return data;
}

export async function fetchTenants(
  limit = 50,
  offset = 0,
  parentId?: string,
  cursor?: string,
  search?: string,
) {
  const { data } = await apiClient.get<TenantListResponse>(
    "/v1/admin/tenants",
    {
      params: { limit, offset, parentId, cursor, search },
    },
  );
  return data;
}

function getAdminApiBaseUrl() {
  if (
    (window as Window & typeof globalThis & { _IS_TEST_MODE?: boolean })
      ._IS_TEST_MODE
  ) {
    return "http://playwright-mock/api";
  }

  return import.meta.env.VITE_ADMIN_API_BASE ?? "/api";
}

async function buildAdminRequestHeaders() {
  const headers: Record<string, string> = {};
  const user = await userManager.getUser();
  const sessionToken =
    user?.access_token || window.localStorage.getItem("admin_session");

  if (sessionToken) {
    headers.Authorization = `Bearer ${sessionToken}`;
  }

  const tenantId = window.localStorage.getItem("admin_tenant");
  if (tenantId) {
    headers["X-Tenant-ID"] = tenantId;
  }

  const isMockRoleEnabled =
    window.localStorage.getItem("X-Mock-Role-Enabled") === "true";
  const mockRole = window.localStorage.getItem("X-Mock-Role");
  if (isMockRoleEnabled && mockRole) {
    headers["X-Test-Role"] = mockRole;
  }

  return headers;
}

export async function fetchAllTenants({
  pageSize = 100,
  parentId,
}: {
  pageSize?: number;
  parentId?: string;
} = {}) {
  return fetchAllCursorPages<TenantSummary>({
    baseUrl: getAdminApiBaseUrl(),
    path: "/v1/admin/tenants",
    pageSize,
    params: { parentId },
    headers: await buildAdminRequestHeaders(),
  }) as Promise<TenantListResponse>;
}

export async function fetchTenant(tenantId: string) {
  const { data } = await apiClient.get<TenantSummary>(
    `/v1/admin/tenants/${tenantId}`,
  );
  return data;
}

export async function createTenant(payload: TenantCreateRequest) {
  const { data } = await apiClient.post<TenantSummary>(
    "/v1/admin/tenants",
    payload,
  );
  return data;
}

export async function updateTenant(
  tenantId: string,
  payload: TenantUpdateRequest,
) {
  const { data } = await apiClient.put<TenantSummary>(
    `/v1/admin/tenants/${tenantId}`,
    payload,
  );
  return data;
}

export async function deleteTenant(tenantId: string) {
  await apiClient.delete(`/v1/admin/tenants/${tenantId}`);
}

export async function deleteTenantsBulk(ids: string[]) {
  await apiClient.delete("/v1/admin/tenants/bulk", {
    data: { ids },
  });
}

export async function exportTenantsCSV(includeIds = false, parentId?: string) {
  const response = await apiClient.get<Blob>("/v1/admin/tenants/export", {
    params: { includeIds, parentId: parentId || undefined },
    responseType: "blob",
  });
  const dispositionHeader = response.headers["content-disposition"];
  const disposition = Array.isArray(dispositionHeader)
    ? dispositionHeader[0]
    : String(dispositionHeader ?? "");
  const filenameMatch = disposition?.match(/filename="?([^"]+)"?/i);
  return {
    blob: response.data,
    filename: filenameMatch?.[1] ?? "tenants.csv",
  };
}

export async function importTenantsCSV(file: File) {
  const formData = new FormData();
  formData.append("file", file);
  const { data } = await apiClient.post<TenantImportResult>(
    "/v1/admin/tenants/import",
    formData,
    {
      headers: {
        "Content-Type": "multipart/form-data",
      },
    },
  );
  return data;
}

export async function approveTenant(tenantId: string) {
  const { data } = await apiClient.post<TenantSummary>(
    `/v1/admin/tenants/${tenantId}/approve`,
  );
  return data;
}

export type TenantAdmin = {
  id: string;
  name: string;
  email: string;
};

export async function fetchTenantAdmins(tenantId: string) {
  const { data } = await apiClient.get<TenantAdmin[]>(
    `/v1/admin/tenants/${tenantId}/admins`,
  );
  return data;
}

export async function addTenantAdmin(tenantId: string, userId: string) {
  await apiClient.post(`/v1/admin/tenants/${tenantId}/admins/${userId}`);
}

export async function removeTenantAdmin(tenantId: string, userId: string) {
  await apiClient.delete(`/v1/admin/tenants/${tenantId}/admins/${userId}`);
}

export async function fetchTenantOwners(tenantId: string) {
  const { data } = await apiClient.get<TenantAdmin[]>(
    `/v1/admin/tenants/${tenantId}/owners`,
  );
  return data;
}

export async function addTenantOwner(tenantId: string, userId: string) {
  await apiClient.post(`/v1/admin/tenants/${tenantId}/owners/${userId}`);
}

export async function removeTenantOwner(tenantId: string, userId: string) {
  await apiClient.delete(`/v1/admin/tenants/${tenantId}/owners/${userId}`);
}

// Group Management
export type GroupMember = {
  id: string;
  name: string;
  email: string;
};

export type GroupSummary = {
  id: string;
  tenantId: string;
  parentId?: string;
  name: string;
  description?: string;
  unitType?: string;
  members?: GroupMember[];
  createdAt?: string;
  updatedAt?: string;
};

export type GroupCreateRequest = {
  name: string;
  parentId?: string;
  description?: string;
  unitType?: string;
};

export async function fetchGroups(tenantId: string) {
  const { data } = await apiClient.get<GroupSummary[]>(
    `/v1/admin/tenants/${tenantId}/organization`,
  );
  return data;
}

export async function fetchGroup(tenantId: string, groupId: string) {
  const { data } = await apiClient.get<GroupSummary>(
    `/v1/admin/tenants/${tenantId}/organization/${groupId}`,
  );
  return data;
}

export async function createGroup(
  tenantId: string,
  payload: GroupCreateRequest,
) {
  const { data } = await apiClient.post<GroupSummary>(
    `/v1/admin/tenants/${tenantId}/organization`,
    payload,
  );
  return data;
}

export async function deleteGroup(tenantId: string, groupId: string) {
  await apiClient.delete(
    `/v1/admin/tenants/${tenantId}/organization/${groupId}`,
  );
}

export async function addGroupMember(
  tenantId: string,
  groupId: string,
  userId: string,
) {
  await apiClient.post(
    `/v1/admin/tenants/${tenantId}/organization/${groupId}/members`,
    { userId },
  );
}

export async function removeGroupMember(
  tenantId: string,
  groupId: string,
  userId: string,
) {
  await apiClient.delete(
    `/v1/admin/tenants/${tenantId}/organization/${groupId}/members/${userId}`,
  );
}

export type GroupRole = {
  tenantId: string;
  tenantName: string;
  relation: string;
};

export async function fetchGroupRoles(tenantId: string, groupId: string) {
  const { data } = await apiClient.get<GroupRole[]>(
    `/v1/admin/tenants/${tenantId}/organization/${groupId}/roles`,
  );
  return data;
}

export async function assignGroupRole(
  tenantId: string,
  groupId: string,
  targetTenantId: string,
  relation: string,
) {
  await apiClient.post(
    `/v1/admin/tenants/${tenantId}/organization/${groupId}/roles`,
    { tenantId: targetTenantId, relation },
  );
}

export async function removeGroupRole(
  tenantId: string,
  groupId: string,
  targetTenantId: string,
  relation: string,
) {
  await apiClient.delete(
    `/v1/admin/tenants/${tenantId}/organization/${groupId}/roles/${targetTenantId}/${relation}`,
  );
}

// API Key Management (M2M)
export type ApiKeyCreateRequest = {
  name: string;
  scopes: string[];
};

export type ApiKeyCreateResponse = {
  apiKey: ApiKeySummary;
  clientSecret: string;
};

export type ApiKeyUpdateScopesRequest = {
  scopes: string[];
};

export async function fetchApiKeys(limit = 50, offset = 0) {
  const { data } = await apiClient.get<ApiKeyListResponse>(
    "/v1/admin/api-keys",
    {
      params: { limit, offset },
    },
  );
  return data;
}

export async function createApiKey(payload: ApiKeyCreateRequest) {
  const { data } = await apiClient.post<ApiKeyCreateResponse>(
    "/v1/admin/api-keys",
    payload,
  );
  return data;
}

export async function updateApiKeyScopes(
  apiKeyId: string,
  payload: ApiKeyUpdateScopesRequest,
) {
  const { data } = await apiClient.patch<ApiKeySummary>(
    `/v1/admin/api-keys/${apiKeyId}`,
    payload,
  );
  return data;
}

export async function rotateApiKeySecret(apiKeyId: string) {
  const { data } = await apiClient.post<ApiKeyCreateResponse>(
    `/v1/admin/api-keys/${apiKeyId}/secret/rotate`,
  );
  return data;
}

export async function deleteApiKey(apiKeyId: string) {
  await apiClient.delete(`/v1/admin/api-keys/${apiKeyId}`);
}

// User Management
export type UserSummary = {
  id: string;
  email: string;
  loginId?: string;
  name: string;
  phone?: string;
  role: string;
  status: string;
  tenantSlug?: string;
  companyCode?: string;
  tenant?: TenantSummary;
  joinedTenants?: TenantSummary[]; // [New] 다중 소속 테넌트 목록
  metadata?: Record<string, unknown>;
  department?: string;
  grade?: string;
  position?: string;
  jobTitle?: string;
  createdAt: string;
  updatedAt: string;
};

export type UserListResponse = {
  items: UserSummary[];
  limit: number;
  offset: number;
  total: number;
  next_cursor?: string;
  nextCursor?: string;
};

export type UserCreateRequest = {
  email: string;
  loginId?: string;
  password?: string;
  name: string;
  phone?: string;
  role?: string;
  tenantSlug?: string;
  department?: string;
  grade?: string;
  position?: string;
  jobTitle?: string;
  primaryTenantId?: string;
  primaryTenantName?: string;
  primaryTenantIsOwner?: boolean;
  additionalAppointments?: UserAppointment[];
  metadata?: Record<string, unknown>;
};

export type UserCreateResponse = UserSummary & {
  initialPassword?: string;
};

export type UserUpdateRequest = {
  email?: string;
  loginId?: string;
  password?: string;
  name?: string;
  phone?: string;
  role?: string;
  status?: string;
  tenantSlug?: string;
  isAddTenant?: boolean;
  isRemoveTenant?: boolean;
  department?: string;
  grade?: string;
  position?: string;
  jobTitle?: string;
  primaryTenantId?: string;
  primaryTenantName?: string;
  primaryTenantIsOwner?: boolean;
  additionalAppointments?: UserAppointment[];
  metadata?: Record<string, unknown>;
};

export type GlobalCustomClaimPermission = "admin_only" | "user_and_admin";

export type GlobalCustomClaimDefinition = {
  key: string;
  label: string;
  valueType:
    | "text"
    | "number"
    | "boolean"
    | "array"
    | "object"
    | "date"
    | "datetime";
  readPermission: GlobalCustomClaimPermission;
  writePermission: GlobalCustomClaimPermission;
  description?: string;
};

export type GlobalCustomClaimDefinitionsResponse = {
  items: GlobalCustomClaimDefinition[];
};

export type UserAppointment = {
  tenantId: string;
  tenantSlug?: string;
  tenantName: string;
  isPrimary?: boolean;
  isOwner?: boolean;
  isAdmin?: boolean;
  isManager?: boolean;
  jobTitle?: string;
  grade?: string;
  position?: string;
};

export type BulkUserAppointment = {
  tenantId?: string;
  tenantSlug?: string;
  tenantName?: string;
  isPrimary?: boolean;
  isOwner?: boolean;
  isAdmin?: boolean;
  isManager?: boolean;
  department?: string;
  grade?: string;
  position?: string;
  jobTitle?: string;
  metadata?: Record<string, unknown>;
};

export type BulkUserItem = {
  email: string;
  loginId?: string;
  name: string;
  phone?: string;
  role?: string;
  tenantId?: string;
  tenantSlug?: string;
  emailDomain?: string;
  department?: string;
  grade?: string;
  position?: string;
  jobTitle?: string;
  additionalAppointments?: BulkUserAppointment[];
  tenantImport?: {
    sourceTenantId?: string;
    slug?: string;
    name?: string;
    type?: string;
    parentTenantId?: string;
    parentTenantSlug?: string;
    parentTenantName?: string;
    memo?: string;
    emailDomain?: string;
  };
  metadata: Record<string, unknown>;
  importErrors?: string[];
};

export type BulkUserResult = {
  email: string;
  originalEmail?: string;
  suggestedEmail?: string;
  status?: string;
  warnings?: string[];
  success: boolean;
  message?: string;
  userId?: string;
  modifiedFields?: string[];
};

export type BulkUserResponse = {
  results: BulkUserResult[];
};

export type WorksmobileOutboxItem = {
  id: string;
  resourceType: string;
  resourceId: string;
  action: string;
  payload?: Record<string, unknown>;
  status: string;
  retryCount: number;
  lastError?: string;
  createdAt: string;
  updatedAt: string;
};

export type WorksmobileOverview = {
  tenant: TenantSummary;
  config: {
    enabled: boolean;
    domainMappings?: Record<string, number>;
    tokenConfigured: boolean;
    adminTenantId?: string;
  };
  recentJobs: WorksmobileOutboxItem[];
};

export type WorksmobileCredentialBatch = {
  batchId: string;
  operation?: string;
  userCount: number;
  pendingCount?: number;
  processingCount?: number;
  processedCount?: number;
  failedCount?: number;
  hasPasswords: boolean;
  deletedAt?: string;
  failures?: WorksmobileCredentialBatchFailure[];
  createdAt?: string;
  updatedAt?: string;
};

export type WorksmobileCredentialBatchFailure = {
  userId?: string;
  email?: string;
  status: string;
  retryCount: number;
  lastError?: string;
  updatedAt?: string;
};

export type WorksmobilePendingJobDeleteResult = {
  deletedCount: number;
};

export type WorksmobileComparisonItem = {
  resourceType: string;
  baronId?: string;
  baronSlug?: string;
  baronName?: string;
  baronEmail?: string;
  baronPrimaryOrgId?: string;
  baronPrimaryOrgSlug?: string;
  baronPrimaryOrgName?: string;
  baronParentId?: string;
  baronParentSlug?: string;
  baronParentName?: string;
  worksmobileId?: string;
  externalKey?: string;
  worksmobileName?: string;
  worksmobileEmail?: string;
  worksmobileLevelId?: string;
  worksmobileLevelName?: string;
  worksmobileTask?: string;
  worksmobileDomainId?: number;
  worksmobileDomainName?: string;
  worksmobilePrimaryOrgId?: string;
  worksmobilePrimaryOrgName?: string;
  worksmobilePrimaryOrgPositionId?: string;
  worksmobilePrimaryOrgPositionName?: string;
  worksmobilePrimaryOrgIsManager?: boolean;
  baronParentWorksmobileId?: string;
  baronParentWorksmobileName?: string;
  baronParentWorksmobileEmail?: string;
  worksmobileParentId?: string;
  worksmobileParentName?: string;
  worksmobileParentEmail?: string;
  worksmobileParentExternalKey?: string;
  worksmobileJobStatus?: string;
  worksmobileJobRetryCount?: number;
  worksmobileLastError?: string;
  worksmobileLastAttemptAt?: string;
  status: string;
};

export type WorksmobileComparison = {
  users: WorksmobileComparisonItem[];
  groups: WorksmobileComparisonItem[];
};

export async function fetchUsers(
  limit = 50,
  offset = 0,
  search?: string,
  tenantSlug?: string,
  cursor?: string,
) {
  const { data } = await apiClient.get<UserListResponse>("/v1/admin/users", {
    params: { limit, offset, search, tenantSlug, cursor },
  });
  return data;
}

export async function fetchUser(userId: string) {
  const { data } = await apiClient.get<UserSummary>(
    `/v1/admin/users/${userId}`,
  );
  return data;
}

export async function fetchGlobalCustomClaimDefinitions() {
  const { data } = await apiClient.get<GlobalCustomClaimDefinitionsResponse>(
    "/v1/admin/global-custom-claims",
  );
  return data;
}

export async function updateGlobalCustomClaimDefinitions(
  payload: GlobalCustomClaimDefinitionsResponse,
) {
  const { data } = await apiClient.put<GlobalCustomClaimDefinitionsResponse>(
    "/v1/admin/global-custom-claims",
    payload,
  );
  return data;
}

export async function createUser(payload: UserCreateRequest) {
  const { data } = await apiClient.post<UserCreateResponse>(
    "/v1/admin/users",
    payload,
  );
  return data;
}

export async function exportUsersCSV(
  search?: string,
  tenantSlug?: string,
  includeIds = false,
) {
  const response = await apiClient.get<Blob>("/v1/admin/users/export", {
    params: { search, tenantSlug, includeIds },
    responseType: "blob",
  });
  const dispositionHeader = response.headers["content-disposition"];
  const disposition = Array.isArray(dispositionHeader)
    ? dispositionHeader[0]
    : String(dispositionHeader ?? "");
  const filenameMatch = disposition?.match(/filename="?([^"]+)"?/i);
  return {
    blob: response.data,
    filename: filenameMatch?.[1] ?? "users.csv",
  };
}

export async function bulkCreateUsers(users: BulkUserItem[]) {
  const { data } = await apiClient.post<BulkUserResponse>(
    "/v1/admin/users/bulk",
    { users },
  );
  return data;
}

export async function fetchWorksmobileOverview(tenantId: string) {
  const { data } = await apiClient.get<WorksmobileOverview>(
    `/v1/admin/tenants/${tenantId}/worksmobile`,
  );
  return data;
}

export async function fetchWorksmobileComparison(
  tenantId: string,
  includeMatched = false,
) {
  const { data } = await apiClient.get<WorksmobileComparison>(
    `/v1/admin/tenants/${tenantId}/worksmobile/comparison`,
    {
      params: { includeMatched },
    },
  );
  return data;
}

export async function fetchWorksmobileCredentialBatches(tenantId: string) {
  const { data } = await apiClient.get<WorksmobileCredentialBatch[]>(
    `/v1/admin/tenants/${tenantId}/worksmobile/credential-batches`,
  );
  return data;
}

export async function downloadWorksmobileInitialPasswordsCSV(
  tenantId: string,
  batchId?: string,
) {
  const trimmedBatchId = batchId?.trim();
  const response = await apiClient.get<Blob>(
    `/v1/admin/tenants/${tenantId}/worksmobile/initial-passwords.csv`,
    {
      ...(trimmedBatchId ? { params: { batchId: trimmedBatchId } } : {}),
      responseType: "blob",
    },
  );
  const dispositionHeader = response.headers["content-disposition"];
  const disposition = Array.isArray(dispositionHeader)
    ? dispositionHeader[0]
    : String(dispositionHeader ?? "");
  const filenameMatch = disposition?.match(/filename="?([^"]+)"?/i);
  return {
    blob: response.data,
    filename: filenameMatch?.[1] ?? "worksmobile_initial_passwords.csv",
  };
}

export async function deleteWorksmobileCredentialBatchPasswords(
  tenantId: string,
  batchId: string,
) {
  const { data } = await apiClient.delete<WorksmobileCredentialBatch>(
    `/v1/admin/tenants/${tenantId}/worksmobile/credential-batches/${encodeURIComponent(batchId)}/passwords`,
  );
  return data;
}

export async function deleteWorksmobilePendingJobs(tenantId: string) {
  const { data } = await apiClient.delete<WorksmobilePendingJobDeleteResult>(
    `/v1/admin/tenants/${tenantId}/worksmobile/jobs/pending`,
  );
  return data;
}

export async function enqueueWorksmobileBackfillDryRun(tenantId: string) {
  const { data } = await apiClient.post(
    `/v1/admin/tenants/${tenantId}/worksmobile/backfill/dry-run`,
  );
  return data;
}

export async function enqueueWorksmobileOrgUnitSync(
  tenantId: string,
  orgUnitId: string,
) {
  const { data } = await apiClient.post<WorksmobileOutboxItem>(
    `/v1/admin/tenants/${tenantId}/worksmobile/orgunits/${encodeURIComponent(orgUnitId)}/sync`,
  );
  return data;
}

export async function enqueueWorksmobileOrgUnitDelete(
  tenantId: string,
  orgUnitId: string,
) {
  const { data } = await apiClient.post<WorksmobileOutboxItem>(
    `/v1/admin/tenants/${tenantId}/worksmobile/orgunits/${encodeURIComponent(orgUnitId)}/delete`,
  );
  return data;
}

export async function enqueueWorksmobileUserSync(
  tenantId: string,
  userId: string,
  credentialBatchId?: string,
  initialPassword?: string,
) {
  const trimmedBatchId = credentialBatchId?.trim();
  const trimmedInitialPassword = initialPassword?.trim();
  const path = `/v1/admin/tenants/${tenantId}/worksmobile/users/${userId}/sync`;
  const body = {
    ...(trimmedBatchId ? { credentialBatchId: trimmedBatchId } : {}),
    ...(trimmedInitialPassword
      ? { initialPassword: trimmedInitialPassword }
      : {}),
  };
  const { data } =
    Object.keys(body).length > 0
      ? await apiClient.post<WorksmobileOutboxItem>(path, body)
      : await apiClient.post<WorksmobileOutboxItem>(path);
  return data;
}

export async function resetWorksmobileUserPassword(
  tenantId: string,
  userId: string,
  credentialBatchId?: string,
) {
  const trimmedBatchId = credentialBatchId?.trim();
  const path = `/v1/admin/tenants/${tenantId}/worksmobile/users/${userId}/password/reset`;
  const { data } = trimmedBatchId
    ? await apiClient.post<WorksmobileOutboxItem>(path, {
        credentialBatchId: trimmedBatchId,
      })
    : await apiClient.post<WorksmobileOutboxItem>(path);
  return data;
}

export async function retryWorksmobileJob(tenantId: string, jobId: string) {
  const { data } = await apiClient.post(
    `/v1/admin/tenants/${tenantId}/worksmobile/jobs/${jobId}/retry`,
  );
  return data;
}

export async function bulkUpdateUsers(payload: {
  userIds: string[];
  status?: string;
  role?: string;
  tenantSlug?: string;
  isAddTenant?: boolean;
  department?: string;
  position?: string;
  grade?: string;
  jobTitle?: string;
}) {
  const { data } = await apiClient.put("/v1/admin/users/bulk", payload);
  return data;
}

export async function bulkDeleteUsers(userIds: string[]) {
  const { data } = await apiClient.delete("/v1/admin/users/bulk", {
    data: { userIds },
  });
  return data;
}

export async function updateUser(userId: string, payload: UserUpdateRequest) {
  const { data } = await apiClient.put<UserSummary>(
    `/v1/admin/users/${userId}`,
    payload,
  );
  return data;
}

export type PasswordPolicyResponse = {
  minLength?: number;
  lowercase?: boolean;
  uppercase?: boolean;
  number?: boolean;
  nonAlphanumeric?: boolean;
  minCharacterTypes?: number;
};

export async function fetchPasswordPolicy() {
  const { data } = await apiClient.get<PasswordPolicyResponse>(
    "/v1/auth/password/policy",
  );
  return data;
}

export async function deleteUser(userId: string) {
  await apiClient.delete(`/v1/admin/users/${userId}`);
}

export type UserRpHistoryItem = {
  client_id: string;
  client_name: string;
  lastLoginAt: string;
  status: string;
};

export async function fetchUserRpHistory(userId: string) {
  const { data } = await apiClient.get<UserRpHistoryItem[]>(
    `/v1/admin/users/${userId}/rp-history`,
  );
  return data;
}

export type UserProfileResponse = {
  id: string;
  email: string;
  name: string;
  phone: string;
  role: string;
  department: string;
  affiliationType: string;
  tenantSlug?: string;
  tenantId?: string;
  metadata?: Record<string, unknown>;
  tenant?: TenantSummary;
  manageableTenants?: TenantSummary[];
};

export async function fetchMe() {
  const { data } = await apiClient.get<UserProfileResponse>("/v1/user/me");
  return data;
}

// Relying Party Management
export type RelyingParty = {
  clientId: string;
  tenantId: string;
  name: string;
  description: string;
  createdAt: string;
  updatedAt: string;
};

export type HydraClientReq = {
  client_id?: string;
  client_name: string;
  client_secret?: string;
  redirect_uris: string[];
  scope?: string;
  token_endpoint_auth_method?: string;
  grant_types?: string[];
  response_types?: string[];
  metadata?: Record<string, unknown>;
};

export async function fetchRelyingParties(tenantId: string) {
  const { data } = await apiClient.get<RelyingParty[]>(
    `/v1/admin/tenants/${tenantId}/relying-parties`,
  );
  return data;
}

export async function fetchAllRelyingParties() {
  const { data } = await apiClient.get<RelyingParty[]>(
    "/v1/admin/relying-parties",
  );
  return data;
}

export async function createRelyingParty(
  tenantId: string,
  payload: HydraClientReq,
) {
  const { data } = await apiClient.post<RelyingParty>(
    `/v1/admin/tenants/${tenantId}/relying-parties`,
    payload,
  );
  return data;
}

export async function fetchRelyingParty(id: string) {
  const { data } = await apiClient.get<{
    relyingParty: RelyingParty;
    oauth2Config: HydraClientReq;
  }>(`/v1/admin/relying-parties/${id}`);
  return data;
}

export async function updateRelyingParty(id: string, payload: HydraClientReq) {
  const { data } = await apiClient.put<RelyingParty>(
    `/v1/admin/relying-parties/${id}`,
    payload,
  );
  return data;
}

export async function deleteRelyingParty(id: string) {
  await apiClient.delete(`/v1/admin/relying-parties/${id}`);
}

export type RPOwner = {
  subject: string;

  name?: string;

  email?: string;

  type: string;
};

export async function fetchRPOwners(clientId: string) {
  const { data } = await apiClient.get<RPOwner[]>(
    `/v1/admin/relying-parties/${clientId}/owners`,
  );

  return data;
}

export async function addRPOwner(clientId: string, subject: string) {
  await apiClient.post(
    `/v1/admin/relying-parties/${clientId}/owners/${subject}`,
  );
}

export async function removeRPOwner(clientId: string, subject: string) {
  await apiClient.delete(
    `/v1/admin/relying-parties/${clientId}/owners/${subject}`,
  );
}
