import type { AccessRequest } from "../../entities/access-request/types";
import type { ServiceAccessException, ServiceAppRole, ServiceGrant, ServiceModuleEntitlement, ServiceModuleId } from "../../entities/access/types";
import type { Client, TaskManagerWorkspaceManagedBy } from "../../entities/client/types";
import type { EngineWorkflowAccessRequest } from "../../entities/engine-workflow-access-request/types";
import type { Invite } from "../../entities/invite/types";
import type { Service } from "../../entities/service/types";
import type { SyncStatus } from "../../entities/sync/types";
import type { TaskerInviteRequest } from "../../entities/tasker-invite-request/types";
import type { ClientGroup, ClientMembership, LauncherUser } from "../../entities/user/types";
import type { LauncherData, LauncherSettings } from "./mockApi";

export type AdminAccessAssignmentValue = Exclude<ServiceAppRole, "owner"> | "deny" | "unset";

export interface ControlPlaneSnapshot {
  actor: {
    id: string;
    name: string;
    email: string | null;
    source: string;
  };
  counts: Record<string, number>;
  data: LauncherData;
}

export interface ControlPlaneMutationResult {
  data: LauncherData;
  ok?: boolean;
  message?: string;
  provisioning?: {
    authentikUserId: string;
    email: string;
    name: string;
    groups: string[];
    created: boolean;
    temporaryPassword: string | null;
  } | null;
}

export type AuthentikSyncHealthState = "ok" | "pending" | "error" | "not_configured";

export interface AuthentikSyncHealth {
  configured: boolean;
  state: AuthentikSyncHealthState;
  checkedAt: string;
  counts: {
    total: number;
    synced: number;
    pending: number;
    freshPending: number;
    stalePending: number;
    errors: number;
    disabled: number;
  };
}

export interface AccessRequestMutationResult extends ControlPlaneMutationResult {
  accessRequest: AccessRequest;
}

export interface AccessRequestApproveResult extends AccessRequestMutationResult {
  invite?: Invite | null;
  membership?: ClientMembership | null;
  user?: LauncherUser | null;
}

export interface TaskerInviteRequestMutationResult extends ControlPlaneMutationResult {
  taskerInviteRequest: TaskerInviteRequest;
  tasker?: {
    ok: boolean;
    invite?: {
      id: string;
      email: string;
      status: string;
      inviteLink?: string | null;
      invite_link?: string | null;
      taskerInviteLink?: string | null;
      tasker_invite_link?: string | null;
      platformInviteLink?: string | null;
    };
  };
}

export interface EngineWorkflowAccessRequestMutationResult extends ControlPlaneMutationResult {
  engineWorkflowAccessRequest: EngineWorkflowAccessRequest;
  engine?: {
    ok: boolean;
    workflowId?: string;
    userId?: string;
    role?: string;
    updatedAt?: string;
  };
}

export interface TaskManagerWorkspaceSummary {
  id: string;
  slug: string;
  name: string;
  managedBy?: TaskManagerWorkspaceManagedBy;
  ownerEmail: string | null;
  memberCount: number;
  projects?: TaskManagerProjectSummary[];
}

export interface TaskManagerProjectSummary {
  id: string;
  workspaceSlug: string;
  name: string;
  identifier: string;
  memberCount: number;
}

export interface TaskManagerWorkspaceMembershipResult {
  created: boolean;
  workspace: TaskManagerWorkspaceSummary;
  member: {
    id: string;
    email: string;
    displayName: string;
  };
  role: number;
  isActive: boolean;
  isBanned: boolean;
}

export interface TaskManagerProjectMembershipResult {
  created: boolean;
  workspace: TaskManagerWorkspaceSummary;
  project: TaskManagerProjectSummary;
  member: {
    id: string;
    email: string;
    displayName: string;
  };
  role: number;
  roleSlug: Exclude<TaskManagerWorkspaceMemberRole, "unset">;
  isActive: boolean;
}

export type TaskManagerWorkspaceMemberRole = "unset" | "guest" | "member" | "admin";

export interface TaskManagerWorkspaceMembershipMutationResult extends ControlPlaneMutationResult {
  taskManager: {
    ok: boolean;
    membership: TaskManagerWorkspaceMembershipResult;
  };
}

export interface TaskManagerWorkspaceMembershipRemoveMutationResult extends ControlPlaneMutationResult {
  taskManager: {
    ok: boolean;
    removed: boolean;
    workspace: TaskManagerWorkspaceSummary;
    member: {
      id: string;
      email: string;
      displayName: string;
    };
  };
}

export interface TaskManagerProjectMembershipMutationResult extends ControlPlaneMutationResult {
  taskManager: {
    ok: boolean;
    membership: TaskManagerProjectMembershipResult;
  };
}

export interface TaskManagerProjectMembershipRemoveMutationResult extends ControlPlaneMutationResult {
  taskManager: {
    ok: boolean;
    removed: boolean;
    workspace: TaskManagerWorkspaceSummary;
    project: TaskManagerProjectSummary;
    member: {
      id: string;
      email: string;
      displayName: string;
    };
  };
}

export async function fetchControlPlaneSnapshot(): Promise<ControlPlaneSnapshot> {
  return requestJson<ControlPlaneSnapshot>("/api/admin/control-plane");
}

export async function fetchAdminTaskManagerWorkspaces(): Promise<{ ok: boolean; workspaces: TaskManagerWorkspaceSummary[] }> {
  return requestJson<{ ok: boolean; workspaces: TaskManagerWorkspaceSummary[] }>("/api/admin/task-manager/workspaces");
}

export async function fetchAdminAuthentikSyncHealth(): Promise<AuthentikSyncHealth> {
  return requestJson<AuthentikSyncHealth>("/api/admin/sync/authentik/health");
}

export async function createAdminClient(payload: Partial<Client>): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>("/api/admin/clients", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function updateAdminClient(clientId: string, patch: Partial<Client>): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/clients/${encodeURIComponent(clientId)}`, {
    method: "PATCH",
    body: JSON.stringify(patch),
  });
}

export async function deleteAdminClient(clientId: string): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/clients/${encodeURIComponent(clientId)}`, { method: "DELETE" });
}

export async function updateAdminUserProfile(userId: string, patch: Partial<LauncherUser>): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/users/${encodeURIComponent(userId)}/profile`, {
    method: "PATCH",
    body: JSON.stringify(patch),
  });
}

export async function deleteAdminUser(userId: string): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/users/${encodeURIComponent(userId)}`, { method: "DELETE" });
}

export async function createAdminUser(payload: {
  clientId: string;
  email: string;
  name?: string;
  role?: ClientMembership["role"];
  groupIds?: string[];
  provisionAuth?: boolean;
  generatePassword?: boolean;
  password?: string;
}): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>("/api/admin/users", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function provisionAdminUserAuthentik(
  userId: string,
  payload: { generatePassword?: boolean; password?: string } = {}
): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/users/${encodeURIComponent(userId)}/provision-authentik`, {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function updateAdminMembership(
  membershipId: string,
  patch: Partial<ClientMembership>
): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/memberships/${encodeURIComponent(membershipId)}`, {
    method: "PATCH",
    body: JSON.stringify(patch),
  });
}

export async function deleteAdminMembership(membershipId: string): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/memberships/${encodeURIComponent(membershipId)}`, { method: "DELETE" });
}

export async function ensureAdminTaskManagerWorkspaceMembership(payload: {
  clientId: string;
  userId: string;
  workspaceSlug?: string;
  role?: Exclude<TaskManagerWorkspaceMemberRole, "unset">;
  setLastWorkspace?: boolean;
}): Promise<TaskManagerWorkspaceMembershipMutationResult> {
  return requestJson<TaskManagerWorkspaceMembershipMutationResult>("/api/admin/task-manager/workspace-memberships/ensure", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function removeAdminTaskManagerWorkspaceMembership(payload: {
  clientId: string;
  userId: string;
  workspaceSlug?: string;
}): Promise<TaskManagerWorkspaceMembershipRemoveMutationResult> {
  return requestJson<TaskManagerWorkspaceMembershipRemoveMutationResult>("/api/admin/task-manager/workspace-memberships/remove", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function ensureAdminTaskManagerProjectMembership(payload: {
  clientId: string;
  userId: string;
  workspaceSlug: string;
  projectId: string;
  role: Exclude<TaskManagerWorkspaceMemberRole, "unset">;
}): Promise<TaskManagerProjectMembershipMutationResult> {
  return requestJson<TaskManagerProjectMembershipMutationResult>("/api/admin/task-manager/project-memberships/ensure", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function removeAdminTaskManagerProjectMembership(payload: {
  clientId: string;
  userId: string;
  workspaceSlug: string;
  projectId: string;
}): Promise<TaskManagerProjectMembershipRemoveMutationResult> {
  return requestJson<TaskManagerProjectMembershipRemoveMutationResult>("/api/admin/task-manager/project-memberships/remove", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function createAdminGroup(payload: Pick<ClientGroup, "clientId"> & Partial<ClientGroup>): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>("/api/admin/groups", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function updateAdminGroup(groupId: string, patch: Partial<ClientGroup>): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/groups/${encodeURIComponent(groupId)}`, {
    method: "PATCH",
    body: JSON.stringify(patch),
  });
}

export async function deleteAdminGroup(groupId: string): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/groups/${encodeURIComponent(groupId)}`, { method: "DELETE" });
}

export async function createAdminService(payload: Partial<Service> = {}): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>("/api/admin/services", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function updateAdminService(serviceId: string, patch: Partial<Service>): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/services/${encodeURIComponent(serviceId)}`, {
    method: "PATCH",
    body: JSON.stringify(patch),
  });
}

export async function reorderAdminServices(orderedServiceIds: string[]): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>("/api/admin/services/reorder", {
    method: "PATCH",
    body: JSON.stringify({ orderedServiceIds }),
  });
}

export async function deleteAdminService(serviceId: string): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/services/${encodeURIComponent(serviceId)}`, { method: "DELETE" });
}

export async function createAdminInvite(
  payload: Pick<Invite, "clientId" | "email" | "role">
): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>("/api/admin/invites", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function updateAdminInvite(inviteId: string, patch: Partial<Invite>): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/invites/${encodeURIComponent(inviteId)}`, {
    method: "PATCH",
    body: JSON.stringify(patch),
  });
}

export async function deleteAdminInvite(inviteId: string): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/invites/${encodeURIComponent(inviteId)}`, { method: "DELETE" });
}

export async function updateAdminAccessRequest(
  accessRequestId: string,
  patch: Partial<Pick<AccessRequest, "targetClientId" | "role" | "comment">>
): Promise<AccessRequestMutationResult> {
  return requestJson<AccessRequestMutationResult>(`/api/admin/access-requests/${encodeURIComponent(accessRequestId)}`, {
    method: "PATCH",
    body: JSON.stringify(patch),
  });
}

export async function approveAdminAccessRequest(
  accessRequestId: string,
  payload: Partial<Pick<AccessRequest, "targetClientId" | "role" | "comment">> = {}
): Promise<AccessRequestApproveResult> {
  return requestJson<AccessRequestApproveResult>(`/api/admin/access-requests/${encodeURIComponent(accessRequestId)}/approve`, {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function rejectAdminAccessRequest(
  accessRequestId: string,
  payload: Partial<Pick<AccessRequest, "comment">> = {}
): Promise<AccessRequestMutationResult> {
  return requestJson<AccessRequestMutationResult>(`/api/admin/access-requests/${encodeURIComponent(accessRequestId)}/reject`, {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function approveAdminTaskerInviteRequest(
  taskerInviteRequestId: string,
  payload: Partial<Pick<TaskerInviteRequest, "comment">> = {}
): Promise<TaskerInviteRequestMutationResult> {
  return requestJson<TaskerInviteRequestMutationResult>(
    `/api/admin/tasker-invite-requests/${encodeURIComponent(taskerInviteRequestId)}/approve`,
    {
      method: "POST",
      body: JSON.stringify(payload),
    }
  );
}

export async function rejectAdminTaskerInviteRequest(
  taskerInviteRequestId: string,
  payload: Partial<Pick<TaskerInviteRequest, "comment">> = {}
): Promise<TaskerInviteRequestMutationResult> {
  return requestJson<TaskerInviteRequestMutationResult>(
    `/api/admin/tasker-invite-requests/${encodeURIComponent(taskerInviteRequestId)}/reject`,
    {
      method: "POST",
      body: JSON.stringify(payload),
    }
  );
}

export async function approveAdminEngineWorkflowAccessRequest(
  engineWorkflowAccessRequestId: string,
  payload: Partial<Pick<EngineWorkflowAccessRequest, "comment" | "requestedServiceRole">> & { serviceRole?: EngineWorkflowAccessRequest["requestedServiceRole"] } = {}
): Promise<EngineWorkflowAccessRequestMutationResult> {
  return requestJson<EngineWorkflowAccessRequestMutationResult>(
    `/api/admin/engine-workflow-access-requests/${encodeURIComponent(engineWorkflowAccessRequestId)}/approve`,
    {
      method: "POST",
      body: JSON.stringify(payload),
    }
  );
}

export async function rejectAdminEngineWorkflowAccessRequest(
  engineWorkflowAccessRequestId: string,
  payload: Partial<Pick<EngineWorkflowAccessRequest, "comment">> = {}
): Promise<EngineWorkflowAccessRequestMutationResult> {
  return requestJson<EngineWorkflowAccessRequestMutationResult>(
    `/api/admin/engine-workflow-access-requests/${encodeURIComponent(engineWorkflowAccessRequestId)}/reject`,
    {
      method: "POST",
      body: JSON.stringify(payload),
    }
  );
}

export async function setAdminUserServiceAccess(payload: {
  userId: string;
  serviceId: string;
  value: AdminAccessAssignmentValue;
}): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>("/api/admin/access/user-service", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function setAdminServiceModuleEntitlement(payload: {
  clientId: string;
  userId: string;
  serviceId: string;
  moduleId: ServiceModuleId;
  enabled: boolean;
}): Promise<ControlPlaneMutationResult & { entitlement?: ServiceModuleEntitlement | null }> {
  return requestJson<ControlPlaneMutationResult & { entitlement?: ServiceModuleEntitlement | null }>("/api/admin/access/service-modules", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function upsertAdminGrant(payload: Partial<ServiceGrant>): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>("/api/admin/access/grants", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function upsertAdminException(payload: Partial<ServiceAccessException>): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>("/api/admin/access/exceptions", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

export async function retryAdminSync(syncId: string): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>(`/api/admin/sync/${encodeURIComponent(syncId)}/retry`, { method: "POST" });
}

export async function updateAdminSettings(patch: Partial<LauncherSettings>): Promise<ControlPlaneMutationResult> {
  return requestJson<ControlPlaneMutationResult>("/api/admin/settings", {
    method: "PATCH",
    body: JSON.stringify(patch),
  });
}

async function requestJson<T>(url: string, init: RequestInit = {}): Promise<T> {
  const headers = new Headers(init.headers);
  if (!headers.has("Content-Type")) {
    headers.set("Content-Type", "application/json");
  }

  const response = await fetch(url, {
    ...init,
    headers,
  });

  if (!response.ok) {
    throw new Error(await readErrorMessage(response));
  }

  return (await response.json()) as T;
}

async function readErrorMessage(response: Response) {
  try {
    const payload = (await response.json()) as { error?: string };
    return payload.error ?? response.statusText;
  } catch {
    return response.statusText;
  }
}
