import { useCallback, useEffect, useState } from "react";

import { shouldStartNextConfigMutation } from "@/features/agents/operations/configMutationGatePolicy";
import type { GatewayStatus } from "@/features/agents/operations/gatewayRestartPolicy";
import { randomUUID } from "@/lib/uuid";

export type ConfigMutationKind =
  | "create-agent"
  | "rename-agent"
  | "delete-agent"
  | "update-agent-execution-role"
  | "update-agent-permissions"
  | "update-agent-skills"
  | "update-skill-setup"
  | "repair-sandbox-tool-allowlist";

type QueuedConfigMutation = {
  id: string;
  kind: ConfigMutationKind;
  label: string;
  requiresIdleAgents: boolean;
  run: () => Promise<void>;
  resolve: () => void;
  reject: (error: unknown) => void;
};

export type ActiveConfigMutation = {
  kind: ConfigMutationKind;
  label: string;
};

const mutationRequiresIdleAgents = (kind: ConfigMutationKind): boolean =>
  kind === "create-agent" || kind === "rename-agent" || kind === "delete-agent";

export function useConfigMutationQueue(params: {
  status: GatewayStatus;
  hasRunningAgents: boolean;
  hasRestartBlockInProgress: boolean;
}) {
  const [queuedConfigMutations, setQueuedConfigMutations] = useState<QueuedConfigMutation[]>([]);
  const [activeConfigMutation, setActiveConfigMutation] = useState<QueuedConfigMutation | null>(
    null
  );

  const enqueueConfigMutation = useCallback(
    (params: {
      kind: ConfigMutationKind;
      label: string;
      run: () => Promise<void>;
      requiresIdleAgents?: boolean;
    }) =>
      new Promise<void>((resolve, reject) => {
        const queued: QueuedConfigMutation = {
          id: randomUUID(),
          kind: params.kind,
          label: params.label,
          requiresIdleAgents: params.requiresIdleAgents ?? mutationRequiresIdleAgents(params.kind),
          run: params.run,
          resolve,
          reject,
        };
        setQueuedConfigMutations((current) => [...current, queued]);
      }),
    []
  );

  useEffect(() => {
    if (
      !shouldStartNextConfigMutation({
        status: params.status,
        hasRunningAgents: params.hasRunningAgents,
        nextMutationRequiresIdleAgents: Boolean(queuedConfigMutations[0]?.requiresIdleAgents),
        hasActiveMutation: Boolean(activeConfigMutation),
        hasRestartBlockInProgress: params.hasRestartBlockInProgress,
        queuedCount: queuedConfigMutations.length,
      })
    ) {
      return;
    }

    const next = queuedConfigMutations[0];
    if (!next) return;
    setQueuedConfigMutations((current) => current.slice(1));
    setActiveConfigMutation(next);
  }, [
    activeConfigMutation,
    params.hasRestartBlockInProgress,
    params.hasRunningAgents,
    params.status,
    queuedConfigMutations,
  ]);

  useEffect(() => {
    if (!activeConfigMutation) return;
    let mounted = true;
    const run = async () => {
      try {
        await activeConfigMutation.run();
        activeConfigMutation.resolve();
      } catch (error) {
        activeConfigMutation.reject(error);
      } finally {
        if (mounted) {
          setActiveConfigMutation(null);
        }
      }
    };
    void run();
    return () => {
      mounted = false;
    };
  }, [activeConfigMutation]);

  return {
    enqueueConfigMutation,
    queuedCount: queuedConfigMutations.length,
    queuedBlockedByRunningAgents:
      Boolean(queuedConfigMutations[0]?.requiresIdleAgents) && params.hasRunningAgents,
    activeConfigMutation: activeConfigMutation
      ? ({ kind: activeConfigMutation.kind, label: activeConfigMutation.label } satisfies ActiveConfigMutation)
      : null,
  };
}
