'use client'

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useRef, useEffect } from 'react'
import { apiGet, apiPost } from '@/lib/api/client'

// Types

export interface NetcupServer {
  id: string
  name: string
  nickname?: string
  state: 'ON' | 'OFF' | 'POWERCYCLE' | 'RESET' | 'POWEROFF' | 'UNKNOWN'
  primaryIpv4?: string
  primaryIpv6?: string
  hostname?: string
  cpuCores?: number
  ramGb?: number
  diskGb?: number
  cpuUsage?: number
  ramUsage?: number
  diskUsage?: number
}

export interface NetcupAuthStatus {
  authenticated: boolean
  expiresAt: string | null
}

export interface DeviceAuthResponse {
  success: boolean
  sessionId: string
  userCode: string
  verificationUri: string
  verificationUriComplete: string
  expiresIn: number
  interval: number
}

export interface PollResponse {
  success: boolean
  status: 'pending' | 'authenticated'
  message?: string
}

export interface ImageFlavour {
  id: string
  name: string
  description?: string
  category: string
}

export interface RescueCredentials {
  password: string
  expiresAt: string
}

export type PowerAction = 'ON' | 'OFF' | 'POWERCYCLE' | 'RESET' | 'POWEROFF'

// Metrics types
export interface MetricsDataPoint {
  timestamp: string
  value: number
}

export interface CpuMetrics {
  dataPoints: MetricsDataPoint[]
  average: number
  max: number
}

export interface DiskMetrics {
  readBps: MetricsDataPoint[]
  writeBps: MetricsDataPoint[]
  readIops: MetricsDataPoint[]
  writeIops: MetricsDataPoint[]
}

export interface NetworkMetrics {
  rxBps: MetricsDataPoint[]
  txBps: MetricsDataPoint[]
}

export interface ServerMetrics {
  cpu: CpuMetrics
  disk: DiskMetrics
  network: NetworkMetrics
  period: string
}

// Snapshot types
export interface Snapshot {
  name: string
  createdAt: string
  size?: number
  description?: string
}

// Portainer status types
export interface PortainerStatus {
  available: boolean
  version?: string
  instanceId?: string | null
  needsSetup?: boolean
  error?: string
}

// Query keys

export const netcupKeys = {
  all: ['netcup'] as const,
  auth: () => [...netcupKeys.all, 'auth'] as const,
  servers: () => [...netcupKeys.all, 'servers'] as const,
  serversList: (liveInfo = true) => [...netcupKeys.servers(), 'list', { liveInfo }] as const,
  server: (id: string) => [...netcupKeys.servers(), id] as const,
  serverWithLive: (id: string) => [...netcupKeys.server(id), 'live'] as const,
  imageFlavours: (id: string) => [...netcupKeys.server(id), 'flavours'] as const,
  metrics: (id: string, hours?: number) => [...netcupKeys.server(id), 'metrics', hours ?? 24] as const,
  snapshots: (id: string) => [...netcupKeys.server(id), 'snapshots'] as const,
  portainerStatus: (ip: string) => [...netcupKeys.all, 'portainer', ip] as const,
  task: (taskId: string) => [...netcupKeys.all, 'task', taskId] as const,
}

// API calls

async function getAuthStatus(): Promise<NetcupAuthStatus> {
  return apiGet<NetcupAuthStatus>('/api/v1/admin/netcup/auth')
}

async function initiateAuth(): Promise<DeviceAuthResponse> {
  return apiPost<DeviceAuthResponse>('/api/v1/admin/netcup/auth', {
    action: 'initiate',
  })
}

async function pollAuth(sessionId: string): Promise<PollResponse> {
  return apiPost<PollResponse>('/api/v1/admin/netcup/auth', {
    action: 'poll',
    sessionId,
  })
}

async function disconnect(): Promise<{ success: boolean }> {
  return apiPost<{ success: boolean }>('/api/v1/admin/netcup/auth', {
    action: 'disconnect',
  })
}

async function getServers(liveInfo = true): Promise<{ servers: NetcupServer[]; count: number }> {
  return apiGet<{ servers: NetcupServer[]; count: number }>('/api/v1/admin/netcup/servers', {
    params: { liveInfo },
  })
}

async function getServer(id: string, liveInfo = false): Promise<NetcupServer> {
  return apiGet<NetcupServer>(`/api/v1/admin/netcup/servers/${id}`, {
    params: { liveInfo },
  })
}

async function performPowerAction(
  serverId: string,
  powerAction: PowerAction
): Promise<{ success: boolean }> {
  return apiPost<{ success: boolean }>(`/api/v1/admin/netcup/servers/${serverId}`, {
    action: 'power',
    powerAction,
  })
}

async function reinstallServer(
  serverId: string,
  imageFlavour: string
): Promise<{ success: boolean; taskId: string }> {
  return apiPost<{ success: boolean; taskId: string }>(
    `/api/v1/admin/netcup/servers/${serverId}`,
    { action: 'reinstall', imageFlavour }
  )
}

async function activateRescue(
  serverId: string
): Promise<{ success: boolean; credentials: RescueCredentials }> {
  return apiPost<{ success: boolean; credentials: RescueCredentials }>(
    `/api/v1/admin/netcup/servers/${serverId}`,
    { action: 'rescue', rescueAction: 'activate' }
  )
}

async function deactivateRescue(serverId: string): Promise<{ success: boolean }> {
  return apiPost<{ success: boolean }>(`/api/v1/admin/netcup/servers/${serverId}`, {
    action: 'rescue',
    rescueAction: 'deactivate',
  })
}

async function updateHostname(
  serverId: string,
  hostname: string
): Promise<{ success: boolean }> {
  return apiPost<{ success: boolean }>(`/api/v1/admin/netcup/servers/${serverId}`, {
    action: 'hostname',
    hostname,
  })
}

async function updateNickname(
  serverId: string,
  nickname: string
): Promise<{ success: boolean }> {
  return apiPost<{ success: boolean }>(`/api/v1/admin/netcup/servers/${serverId}`, {
    action: 'nickname',
    nickname,
  })
}

async function getImageFlavours(
  serverId: string
): Promise<{ success: boolean; flavours: ImageFlavour[] }> {
  return apiPost<{ success: boolean; flavours: ImageFlavour[] }>(
    `/api/v1/admin/netcup/servers/${serverId}`,
    { action: 'imageFlavours' }
  )
}

// Metrics API calls

async function getServerMetrics(
  serverId: string,
  hours = 24
): Promise<ServerMetrics> {
  return apiGet<ServerMetrics>(`/api/v1/admin/netcup/servers/${serverId}/metrics`, {
    params: { hours },
  })
}

// Snapshot API calls

async function getSnapshots(
  serverId: string
): Promise<{ snapshots: Snapshot[]; count: number }> {
  return apiGet<{ snapshots: Snapshot[]; count: number }>(
    `/api/v1/admin/netcup/servers/${serverId}/snapshots`
  )
}

async function createSnapshot(
  serverId: string,
  name?: string
): Promise<{ success: boolean; message: string; snapshot?: { name: string } }> {
  return apiPost<{ success: boolean; message: string; snapshot?: { name: string } }>(
    `/api/v1/admin/netcup/servers/${serverId}/snapshots`,
    { action: 'create', name }
  )
}

async function deleteSnapshot(
  serverId: string,
  name: string
): Promise<{ success: boolean; message: string }> {
  return apiPost<{ success: boolean; message: string }>(
    `/api/v1/admin/netcup/servers/${serverId}/snapshots`,
    { action: 'delete', name }
  )
}

async function revertSnapshot(
  serverId: string,
  name: string
): Promise<{ success: boolean; message: string; taskId?: string }> {
  return apiPost<{ success: boolean; message: string; taskId?: string }>(
    `/api/v1/admin/netcup/servers/${serverId}/snapshots`,
    { action: 'revert', name }
  )
}

async function checkCanCreateSnapshot(
  serverId: string
): Promise<{ possible: boolean; reason?: string }> {
  return apiPost<{ possible: boolean; reason?: string }>(
    `/api/v1/admin/netcup/servers/${serverId}/snapshots`,
    { action: 'check' }
  )
}

async function checkPortainerStatus(
  ip: string,
  port = '9443'
): Promise<PortainerStatus> {
  return apiGet<PortainerStatus>('/api/v1/admin/portainer/ping', {
    params: { ip, port },
  })
}

// Task status types
export interface TaskStatus {
  taskId: string
  status: 'PENDING' | 'RUNNING' | 'COMPLETED' | 'FAILED' | 'UNKNOWN'
  progress?: number
  message?: string
  result?: unknown
  error?: string
}

async function getTaskStatus(taskId: string): Promise<TaskStatus> {
  return apiGet<TaskStatus>(`/api/v1/admin/netcup/tasks/${taskId}`)
}

// Hooks

export function useNetcupAuth() {
  return useQuery({
    queryKey: netcupKeys.auth(),
    queryFn: getAuthStatus,
    staleTime: 1000 * 60, // 1 minute
  })
}

export function useNetcupServers(liveInfo = true) {
  return useQuery({
    queryKey: netcupKeys.serversList(liveInfo),
    queryFn: () => getServers(liveInfo),
    // Live info takes longer, so increase stale time
    staleTime: liveInfo ? 1000 * 30 : 1000 * 10, // 30s with live info, 10s without
  })
}

export function useNetcupServer(id: string, liveInfo = false) {
  return useQuery({
    queryKey: liveInfo ? netcupKeys.serverWithLive(id) : netcupKeys.server(id),
    queryFn: () => getServer(id, liveInfo),
    enabled: !!id,
  })
}

export function useNetcupImageFlavours(serverId: string) {
  return useQuery({
    queryKey: netcupKeys.imageFlavours(serverId),
    queryFn: () => getImageFlavours(serverId),
    enabled: !!serverId,
  })
}

export function useInitiateNetcupAuth() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: initiateAuth,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: netcupKeys.auth() })
    },
  })
}

export function usePollNetcupAuth() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: pollAuth,
    onSuccess: (data) => {
      if (data.status === 'authenticated') {
        queryClient.invalidateQueries({ queryKey: netcupKeys.auth() })
        // Invalidate all server-related queries
        queryClient.invalidateQueries({ queryKey: netcupKeys.servers() })
      }
    },
  })
}

export function useDisconnectNetcup() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: disconnect,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: netcupKeys.auth() })
      // Invalidate all server-related queries
      queryClient.invalidateQueries({ queryKey: netcupKeys.servers() })
    },
  })
}

// Track pending power actions and their expected final states
const pendingPowerActions = new Map<string, { expectedState: 'ON' | 'OFF'; startTime: number }>()

// Track servers that are being reinstalled (minimum 5 minutes)
const REINSTALL_MIN_DURATION_MS = 5 * 60 * 1000 // 5 minutes
const pendingReinstalls = new Map<string, { startTime: number }>()

// Mark a server as being reinstalled
export function markServerReinstalling(serverId: string): void {
  pendingReinstalls.set(serverId, { startTime: Date.now() })
}

// Clear reinstall state for a server
export function clearServerReinstalling(serverId: string): void {
  pendingReinstalls.delete(serverId)
}

// Check if a server is currently being reinstalled
export function isServerReinstalling(serverId: string): boolean {
  const pending = pendingReinstalls.get(serverId)
  if (!pending) return false

  const elapsed = Date.now() - pending.startTime
  if (elapsed >= REINSTALL_MIN_DURATION_MS) {
    pendingReinstalls.delete(serverId)
    return false
  }
  return true
}

export function useNetcupPowerAction() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ serverId, action }: { serverId: string; action: PowerAction }) =>
      performPowerAction(serverId, action),
    onMutate: async ({ serverId, action }) => {
      // Cancel any outgoing refetches
      await queryClient.cancelQueries({ queryKey: netcupKeys.server(serverId) })
      await queryClient.cancelQueries({ queryKey: netcupKeys.servers() })

      // Snapshot previous values
      const previousServer = queryClient.getQueryData<NetcupServer>(netcupKeys.server(serverId))
      const previousServerLive = queryClient.getQueryData<NetcupServer>(netcupKeys.serverWithLive(serverId))

      // Determine the transitional state to show and expected final state
      let transitionalState: string
      let expectedState: 'ON' | 'OFF'

      switch (action) {
        case 'ON':
          transitionalState = 'POWERON' // Shows "Powering On"
          expectedState = 'ON'
          break
        case 'OFF':
          transitionalState = 'POWEROFF' // Shows "Shutting Down"
          expectedState = 'OFF'
          break
        case 'POWERCYCLE':
        case 'RESET':
          transitionalState = action // Shows "Restarting" or "Hard Resetting"
          expectedState = 'ON' // Server should come back ON
          break
        case 'POWEROFF':
          transitionalState = action // Shows "Shutting Down"
          expectedState = 'OFF'
          break
        default:
          transitionalState = action
          expectedState = 'ON'
      }

      // Track this power action
      pendingPowerActions.set(serverId, { expectedState, startTime: Date.now() })

      // Optimistically update the server state
      if (previousServer) {
        queryClient.setQueryData<NetcupServer>(netcupKeys.server(serverId), {
          ...previousServer,
          state: transitionalState as NetcupServer['state'],
        })
      }
      if (previousServerLive) {
        queryClient.setQueryData<NetcupServer>(netcupKeys.serverWithLive(serverId), {
          ...previousServerLive,
          state: transitionalState as NetcupServer['state'],
        })
      }

      // Optimistically update server lists
      queryClient.setQueriesData<{ servers: NetcupServer[]; count: number } | undefined>(
        { queryKey: netcupKeys.servers() },
        (old) => {
          if (!old?.servers) return old
          return {
            ...old,
            servers: old.servers.map((s) =>
              s.id === serverId ? { ...s, state: transitionalState as NetcupServer['state'] } : s
            ),
          }
        }
      )

      return { previousServer, previousServerLive }
    },
    onError: (_, { serverId }, context) => {
      // Rollback on error and clear pending action
      pendingPowerActions.delete(serverId)
      if (context?.previousServer) {
        queryClient.setQueryData(netcupKeys.server(serverId), context.previousServer)
      }
      if (context?.previousServerLive) {
        queryClient.setQueryData(netcupKeys.serverWithLive(serverId), context.previousServerLive)
      }
    },
    onSettled: async (_, __, { serverId }) => {
      // Don't invalidate - let polling handle state updates
      // The pending action will be cleared when we reach the expected state
    },
  })
}

// Check if we should update the UI with a new state from the API
export function shouldUpdateServerState(serverId: string, newState: string): boolean {
  // Check if server is being reinstalled - don't update state during reinstall
  if (isServerReinstalling(serverId)) {
    return false // Keep showing REINSTALLING state
  }

  // Check for pending power actions
  const pending = pendingPowerActions.get(serverId)
  if (!pending) return true // No pending action, always update

  // If we've been waiting more than 2 minutes, give up and update
  if (Date.now() - pending.startTime > 120000) {
    pendingPowerActions.delete(serverId)
    return true
  }

  // Only update if we've reached the expected final state
  if (newState === pending.expectedState) {
    pendingPowerActions.delete(serverId)
    return true
  }

  // Don't update - keep showing transitional state
  return false
}

export function useNetcupReinstall() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({
      serverId,
      imageFlavour,
    }: {
      serverId: string
      imageFlavour: string
    }) => reinstallServer(serverId, imageFlavour),
    onMutate: async ({ serverId }) => {
      // Cancel outgoing refetches
      await queryClient.cancelQueries({ queryKey: netcupKeys.server(serverId) })

      // Mark server as reinstalling - this prevents state updates for 5 minutes
      markServerReinstalling(serverId)

      // Snapshot previous values
      const previousServer = queryClient.getQueryData<NetcupServer>(netcupKeys.server(serverId))
      const previousServerLive = queryClient.getQueryData<NetcupServer>(netcupKeys.serverWithLive(serverId))

      // Optimistically update to REINSTALLING state
      if (previousServer) {
        queryClient.setQueryData<NetcupServer>(netcupKeys.server(serverId), {
          ...previousServer,
          state: 'REINSTALLING' as NetcupServer['state'],
        })
      }
      if (previousServerLive) {
        queryClient.setQueryData<NetcupServer>(netcupKeys.serverWithLive(serverId), {
          ...previousServerLive,
          state: 'REINSTALLING' as NetcupServer['state'],
        })
      }

      // Update server lists
      queryClient.setQueriesData<{ servers: NetcupServer[]; count: number } | undefined>(
        { queryKey: netcupKeys.servers() },
        (old) => {
          if (!old?.servers) return old
          return {
            ...old,
            servers: old.servers.map((s) =>
              s.id === serverId ? { ...s, state: 'REINSTALLING' as NetcupServer['state'] } : s
            ),
          }
        }
      )

      return { previousServer, previousServerLive }
    },
    onError: (_, { serverId }, context) => {
      // Clear reinstall state on error
      clearServerReinstalling(serverId)
      // Rollback optimistic update
      if (context?.previousServer) {
        queryClient.setQueryData(netcupKeys.server(serverId), context.previousServer)
      }
      if (context?.previousServerLive) {
        queryClient.setQueryData(netcupKeys.serverWithLive(serverId), context.previousServerLive)
      }
    },
    // Don't invalidate on settled - let the pendingReinstalls timer handle when to refresh
    // The shouldUpdateServerState check will prevent premature state updates
  })
}

export function useNetcupRescue() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({
      serverId,
      activate,
    }: {
      serverId: string
      activate: boolean
    }) => (activate ? activateRescue(serverId) : deactivateRescue(serverId)),
    onSuccess: (_, { serverId }) => {
      queryClient.invalidateQueries({ queryKey: netcupKeys.server(serverId) })
    },
  })
}

export function useNetcupUpdateHostname() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ serverId, hostname }: { serverId: string; hostname: string }) =>
      updateHostname(serverId, hostname),
    onSuccess: (_, { serverId }) => {
      queryClient.invalidateQueries({ queryKey: netcupKeys.server(serverId) })
      // Invalidate all server lists
      queryClient.invalidateQueries({ queryKey: netcupKeys.servers() })
    },
  })
}

export function useNetcupUpdateNickname() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ serverId, nickname }: { serverId: string; nickname: string }) =>
      updateNickname(serverId, nickname),
    onSuccess: (_, { serverId }) => {
      queryClient.invalidateQueries({ queryKey: netcupKeys.server(serverId) })
      // Invalidate all server lists
      queryClient.invalidateQueries({ queryKey: netcupKeys.servers() })
    },
  })
}

// Live Status Fetch Hook
export function useFetchLiveStatus() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: (serverId: string) => getServer(serverId, true),
    onSuccess: (data, serverId) => {
      // Check if we should update based on pending power actions
      if (!shouldUpdateServerState(serverId, data.state)) {
        return // Don't update - keep showing transitional state
      }

      // Update server in cache with live data
      queryClient.setQueryData(netcupKeys.serverWithLive(serverId), data)
      queryClient.setQueryData(netcupKeys.server(serverId), data)
      // Update all server lists with the new status (both live and non-live cache keys)
      queryClient.setQueriesData<{ servers: NetcupServer[]; count: number } | undefined>(
        { queryKey: netcupKeys.servers() },
        (old) => {
          if (!old?.servers) return old
          return {
            ...old,
            servers: old.servers.map((s) =>
              s.id === serverId ? { ...s, ...data } : s
            ),
          }
        }
      )
    },
  })
}

// Helper to check if server is in transitional state
export function isTransitionalState(state: string): boolean {
  return ['POWERCYCLE', 'RESET', 'POWEROFF', 'POWERON', 'REINSTALLING'].includes(state)
}

// Metrics Hooks
export function useServerMetrics(serverId: string, hours = 24, enabled = true) {
  return useQuery({
    queryKey: netcupKeys.metrics(serverId, hours),
    queryFn: () => getServerMetrics(serverId, hours),
    enabled: !!serverId && enabled,
    staleTime: 1000 * 60 * 5, // 5 minutes
  })
}

export function useRefreshMetrics() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ serverId, hours = 24 }: { serverId: string; hours?: number }) =>
      getServerMetrics(serverId, hours),
    onSuccess: (data, { serverId, hours = 24 }) => {
      queryClient.setQueryData(netcupKeys.metrics(serverId, hours), data)
    },
  })
}

// Snapshot Hooks
export function useServerSnapshots(serverId: string, enabled = true) {
  return useQuery({
    queryKey: netcupKeys.snapshots(serverId),
    queryFn: () => getSnapshots(serverId),
    enabled: !!serverId && enabled,
  })
}

export function useCreateSnapshot() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ serverId, name }: { serverId: string; name?: string }) =>
      createSnapshot(serverId, name),
    onSuccess: (_, { serverId }) => {
      queryClient.invalidateQueries({ queryKey: netcupKeys.snapshots(serverId) })
    },
  })
}

export function useDeleteSnapshot() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ serverId, name }: { serverId: string; name: string }) =>
      deleteSnapshot(serverId, name),
    onSuccess: (_, { serverId }) => {
      queryClient.invalidateQueries({ queryKey: netcupKeys.snapshots(serverId) })
    },
  })
}

export function useRevertSnapshot() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: ({ serverId, name }: { serverId: string; name: string }) =>
      revertSnapshot(serverId, name),
    onSuccess: (_, { serverId }) => {
      queryClient.invalidateQueries({ queryKey: netcupKeys.snapshots(serverId) })
      queryClient.invalidateQueries({ queryKey: netcupKeys.server(serverId) })
    },
  })
}

export function useCheckCanCreateSnapshot() {
  return useMutation({
    mutationFn: (serverId: string) => checkCanCreateSnapshot(serverId),
  })
}

// Portainer Status Hook
export function usePortainerStatus(ip: string | undefined, enabled = true) {
  return useQuery({
    queryKey: netcupKeys.portainerStatus(ip || ''),
    queryFn: () => checkPortainerStatus(ip!),
    enabled: !!ip && enabled,
    staleTime: 1000 * 60 * 5, // 5 minutes
    retry: false, // Don't retry on failure - server might just not have Portainer
  })
}

// Task Status Hook - polls for long-running operations like reinstall
export function useTaskStatus(
  taskId: string | null | undefined,
  options?: {
    onCompleted?: () => void
    onFailed?: (error: string) => void
    pollInterval?: number
  }
) {
  const queryClient = useQueryClient()
  const { onCompleted, onFailed, pollInterval = 5000 } = options || {}

  // Track previous status to detect changes (prevent repeated callback calls)
  const prevStatusRef = useRef<string | undefined>(undefined)
  const callbacksFiredRef = useRef<{ completed: boolean; failed: boolean }>({ completed: false, failed: false })

  const query = useQuery({
    queryKey: netcupKeys.task(taskId || ''),
    queryFn: () => getTaskStatus(taskId!),
    enabled: !!taskId,
    refetchInterval: (q) => {
      const data = q.state.data
      // Stop polling when task is done
      if (data?.status === 'COMPLETED' || data?.status === 'FAILED') {
        return false
      }
      return pollInterval
    },
    refetchIntervalInBackground: true,
  })

  // Handle callbacks via useEffect - only fire once when status changes to terminal state
  useEffect(() => {
    const currentStatus = query.data?.status

    // Reset callback tracking when taskId changes
    if (!taskId) {
      prevStatusRef.current = undefined
      callbacksFiredRef.current = { completed: false, failed: false }
      return
    }

    // Only process if status actually changed
    if (currentStatus && currentStatus !== prevStatusRef.current) {
      prevStatusRef.current = currentStatus

      // Fire onCompleted exactly once when task completes
      if (currentStatus === 'COMPLETED' && onCompleted && !callbacksFiredRef.current.completed) {
        callbacksFiredRef.current.completed = true
        onCompleted()
        // Note: We do NOT invalidate server queries here - let the page handle state
        // The reinstall minimum duration logic in the page will control when to refresh
      }

      // Fire onFailed exactly once when task fails
      if (currentStatus === 'FAILED' && onFailed && !callbacksFiredRef.current.failed) {
        callbacksFiredRef.current.failed = true
        onFailed(query.data?.error || 'Task failed')
      }
    }
  }, [taskId, query.data?.status, query.data?.error, onCompleted, onFailed])

  // Reset refs when taskId changes
  useEffect(() => {
    prevStatusRef.current = undefined
    callbacksFiredRef.current = { completed: false, failed: false }
  }, [taskId])

  return query
}
