import { useCallback, useMemo, useRef } from 'react';
import { trpc } from '@/lib/trpc';
import type { PendingQuestions } from '@codewalk-district/shared';

export type ConflictAgentState = 'none' | 'running' | 'waiting' | 'completed' | 'crashed';

type ConflictAgent = NonNullable<ReturnType<typeof trpc.getActiveConflictAgent.useQuery>['data']>;

export interface UseConflictAgentResult {
  agent: ConflictAgent | null;
  state: ConflictAgentState;
  questions: PendingQuestions | null;
  spawn: {
    mutate: (options: { initiativeId: string; provider?: string }) => void;
    isPending: boolean;
    error: Error | null;
  };
  resume: {
    mutate: (answers: Record<string, string>) => void;
    isPending: boolean;
    error: Error | null;
  };
  stop: {
    mutate: () => void;
    isPending: boolean;
  };
  dismiss: () => void;
  isLoading: boolean;
  refresh: () => void;
}

export function useConflictAgent(initiativeId: string): UseConflictAgentResult {
  const utils = trpc.useUtils();

  const agentQuery = trpc.getActiveConflictAgent.useQuery({ initiativeId });
  const agent = agentQuery.data ?? null;

  const state: ConflictAgentState = useMemo(() => {
    if (!agent) return 'none';
    switch (agent.status) {
      case 'running':
        return 'running';
      case 'waiting_for_input':
        return 'waiting';
      case 'idle':
        return 'completed';
      case 'crashed':
        return 'crashed';
      default:
        return 'none';
    }
  }, [agent]);

  const questionsQuery = trpc.getAgentQuestions.useQuery(
    { id: agent?.id ?? '' },
    { enabled: state === 'waiting' && !!agent },
  );

  const spawnMutation = trpc.spawnConflictResolutionAgent.useMutation({
    onMutate: async () => {
      await utils.listAgents.cancel();
      await utils.getActiveConflictAgent.cancel({ initiativeId });

      const previousAgents = utils.listAgents.getData();
      const previousConflictAgent = utils.getActiveConflictAgent.getData({ initiativeId });

      const tempAgent = {
        id: `temp-${Date.now()}`,
        name: `conflict-${Date.now()}`,
        mode: 'execute' as const,
        status: 'running' as const,
        initiativeId,
        taskId: null,
        phaseId: null,
        provider: 'claude',
        accountId: null,
        instruction: null,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString(),
        userDismissedAt: null,
        completedAt: null,
      };

      utils.listAgents.setData(undefined, (old = []) => [tempAgent, ...old]);
      utils.getActiveConflictAgent.setData({ initiativeId }, tempAgent as any);

      return { previousAgents, previousConflictAgent };
    },
    onError: (_err, _variables, context) => {
      if (context?.previousAgents) {
        utils.listAgents.setData(undefined, context.previousAgents);
      }
      if (context?.previousConflictAgent !== undefined) {
        utils.getActiveConflictAgent.setData({ initiativeId }, context.previousConflictAgent);
      }
    },
    onSettled: () => {
      void utils.listAgents.invalidate();
      void utils.getActiveConflictAgent.invalidate({ initiativeId });
    },
  });

  const resumeMutation = trpc.resumeAgent.useMutation({
    onSuccess: () => {
      void utils.listAgents.invalidate();
    },
  });

  const stopMutation = trpc.stopAgent.useMutation({
    onSuccess: () => {
      void utils.listAgents.invalidate();
      void utils.listWaitingAgents.invalidate();
    },
  });

  const dismissMutation = trpc.dismissAgent.useMutation({
    onMutate: async ({ id }) => {
      await utils.listAgents.cancel();
      await utils.getActiveConflictAgent.cancel({ initiativeId });

      const previousAgents = utils.listAgents.getData();
      const previousConflictAgent = utils.getActiveConflictAgent.getData({ initiativeId });

      utils.listAgents.setData(undefined, (old = []) => old.filter(a => a.id !== id));
      utils.getActiveConflictAgent.setData({ initiativeId }, null);

      return { previousAgents, previousConflictAgent };
    },
    onError: (_err, _variables, context) => {
      if (context?.previousAgents) {
        utils.listAgents.setData(undefined, context.previousAgents);
      }
      if (context?.previousConflictAgent !== undefined) {
        utils.getActiveConflictAgent.setData({ initiativeId }, context.previousConflictAgent);
      }
    },
    onSettled: () => {
      void utils.listAgents.invalidate();
      void utils.getActiveConflictAgent.invalidate({ initiativeId });
    },
  });

  const spawnMutateRef = useRef(spawnMutation.mutate);
  spawnMutateRef.current = spawnMutation.mutate;
  const agentRef = useRef(agent);
  agentRef.current = agent;
  const resumeMutateRef = useRef(resumeMutation.mutate);
  resumeMutateRef.current = resumeMutation.mutate;
  const stopMutateRef = useRef(stopMutation.mutate);
  stopMutateRef.current = stopMutation.mutate;
  const dismissMutateRef = useRef(dismissMutation.mutate);
  dismissMutateRef.current = dismissMutation.mutate;

  const spawnFn = useCallback(({ initiativeId, provider }: { initiativeId: string; provider?: string }) => {
    spawnMutateRef.current({ initiativeId, provider });
  }, []);

  const spawn = useMemo(() => ({
    mutate: spawnFn,
    isPending: spawnMutation.isPending,
    error: spawnMutation.error,
  }), [spawnFn, spawnMutation.isPending, spawnMutation.error]);

  const resumeFn = useCallback((answers: Record<string, string>) => {
    const a = agentRef.current;
    if (a) {
      resumeMutateRef.current({ id: a.id, answers });
    }
  }, []);

  const resume = useMemo(() => ({
    mutate: resumeFn,
    isPending: resumeMutation.isPending,
    error: resumeMutation.error,
  }), [resumeFn, resumeMutation.isPending, resumeMutation.error]);

  const stopFn = useCallback(() => {
    const a = agentRef.current;
    if (a) {
      stopMutateRef.current({ id: a.id });
    }
  }, []);

  const stop = useMemo(() => ({
    mutate: stopFn,
    isPending: stopMutation.isPending,
  }), [stopFn, stopMutation.isPending]);

  const dismiss = useCallback(() => {
    const a = agentRef.current;
    if (a) {
      dismissMutateRef.current({ id: a.id });
    }
  }, []);

  const refresh = useCallback(() => {
    void utils.getActiveConflictAgent.invalidate({ initiativeId });
  }, [utils, initiativeId]);

  const isLoading = agentQuery.isLoading ||
    (state === 'waiting' && questionsQuery.isLoading);

  return {
    agent,
    state,
    questions: questionsQuery.data ?? null,
    spawn,
    resume,
    stop,
    dismiss,
    isLoading,
    refresh,
  };
}
