'use client'

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'

// Types
export interface PortainerCredentials {
  url: string | null
  username: string | null
  password: string | null
  syncedAt: string | null
  isConfigured: boolean
}

export interface Container {
  id: string
  shortId: string
  name: string
  image: string
  state: string
  status: string
  created: number
  ports: Array<{
    private: number
    public?: number
    type: string
  }>
}

export interface ContainerDetails extends Container {
  config: {
    hostname: string
    image: string
    workingDir: string
    env: string[]
  }
  hostConfig: {
    restartPolicy: {
      Name: string
      MaximumRetryCount: number
    }
  }
  networks: Record<string, { IPAddress: string }>
}

export interface ContainerStats {
  cpuPercent: number
  memoryUsage: number // bytes
  memoryLimit: number // bytes
  memoryPercent: number
  networkRx: number // bytes
  networkTx: number // bytes
}

// Query keys
export const portainerKeys = {
  all: ['portainer'] as const,
  credentials: (orderId: string) => [...portainerKeys.all, 'credentials', orderId] as const,
  containers: (orderId: string) => [...portainerKeys.all, 'containers', orderId] as const,
  containerStats: (orderId: string) => [...portainerKeys.all, 'containerStats', orderId] as const,
  container: (orderId: string, containerId: string) =>
    [...portainerKeys.containers(orderId), containerId] as const,
  containerLogs: (orderId: string, containerId: string) =>
    [...portainerKeys.container(orderId, containerId), 'logs'] as const,
  singleContainerStats: (orderId: string, containerId: string) =>
    [...portainerKeys.container(orderId, containerId), 'stats'] as const,
}

// Fetch functions
async function fetchCredentials(orderId: string): Promise<PortainerCredentials> {
  const response = await fetch(`/api/v1/admin/orders/${orderId}/portainer`)
  if (!response.ok) {
    throw new Error('Failed to fetch Portainer credentials')
  }
  return response.json()
}

async function fetchContainers(orderId: string): Promise<Container[]> {
  const response = await fetch(`/api/v1/admin/orders/${orderId}/containers`)
  if (!response.ok) {
    throw new Error('Failed to fetch containers')
  }
  return response.json()
}

async function fetchContainerDetails(
  orderId: string,
  containerId: string
): Promise<ContainerDetails> {
  const response = await fetch(`/api/v1/admin/orders/${orderId}/containers/${containerId}`)
  if (!response.ok) {
    throw new Error('Failed to fetch container details')
  }
  return response.json()
}

async function fetchContainerLogs(
  orderId: string,
  containerId: string,
  tail: number = 100
): Promise<string> {
  const response = await fetch(
    `/api/v1/admin/orders/${orderId}/containers/${containerId}/logs?tail=${tail}`
  )
  if (!response.ok) {
    throw new Error('Failed to fetch container logs')
  }
  const data = await response.json()
  return data.logs
}

async function fetchContainerStats(
  orderId: string
): Promise<Record<string, ContainerStats>> {
  const response = await fetch(`/api/v1/admin/orders/${orderId}/containers/stats`)
  if (!response.ok) {
    throw new Error('Failed to fetch container stats')
  }
  return response.json()
}

async function fetchSingleContainerStats(
  orderId: string,
  containerId: string
): Promise<ContainerStats | null> {
  const response = await fetch(`/api/v1/admin/orders/${orderId}/containers/${containerId}/stats`)
  if (response.status === 404) {
    return null // Container not running
  }
  if (!response.ok) {
    throw new Error('Failed to fetch container stats')
  }
  return response.json()
}

// Hooks

/**
 * Fetch Portainer credentials for an order
 * @param orderId - The order ID
 * @param pollUntilConfigured - If true, poll every 5 seconds until credentials are configured
 */
export function usePortainerCredentials(orderId: string, pollUntilConfigured: boolean = false) {
  return useQuery({
    queryKey: portainerKeys.credentials(orderId),
    queryFn: () => fetchCredentials(orderId),
    enabled: !!orderId,
    // Poll every 5 seconds if credentials aren't configured yet and polling is enabled
    refetchInterval: (query) => {
      if (!pollUntilConfigured) return false
      const data = query.state.data
      // Stop polling once credentials are configured
      if (data?.isConfigured) return false
      return 5000
    },
  })
}

/**
 * Update Portainer credentials
 */
export function useUpdatePortainerCredentials() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async ({
      orderId,
      username,
      password,
    }: {
      orderId: string
      username: string
      password: string
    }) => {
      const response = await fetch(`/api/v1/admin/orders/${orderId}/portainer`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password }),
      })
      if (!response.ok) {
        throw new Error('Failed to update Portainer credentials')
      }
      return response.json()
    },
    onSuccess: (_, { orderId }) => {
      queryClient.invalidateQueries({ queryKey: portainerKeys.credentials(orderId) })
    },
  })
}

/**
 * Test Portainer connection
 */
export function useTestPortainerConnection() {
  return useMutation({
    mutationFn: async (orderId: string) => {
      const response = await fetch(`/api/v1/admin/orders/${orderId}/portainer`, {
        method: 'POST',
      })
      if (!response.ok) {
        throw new Error('Failed to test Portainer connection')
      }
      return response.json() as Promise<{ success: boolean; error?: string }>
    },
  })
}

/**
 * Fetch containers for an order
 */
export function useContainers(orderId: string, enabled: boolean = true) {
  return useQuery({
    queryKey: portainerKeys.containers(orderId),
    queryFn: () => fetchContainers(orderId),
    enabled: !!orderId && enabled,
    refetchInterval: 5000, // Refresh every 5 seconds
  })
}

/**
 * Fetch container details
 */
export function useContainerDetails(orderId: string, containerId: string) {
  return useQuery({
    queryKey: portainerKeys.container(orderId, containerId),
    queryFn: () => fetchContainerDetails(orderId, containerId),
    enabled: !!orderId && !!containerId,
  })
}

/**
 * Fetch container logs
 */
export function useContainerLogs(orderId: string, containerId: string, tail: number = 100) {
  return useQuery({
    queryKey: portainerKeys.containerLogs(orderId, containerId),
    queryFn: () => fetchContainerLogs(orderId, containerId, tail),
    enabled: !!orderId && !!containerId,
  })
}

/**
 * Fetch container stats (CPU, memory, network) for all running containers
 */
export function useContainerStats(orderId: string, enabled: boolean = true) {
  return useQuery({
    queryKey: portainerKeys.containerStats(orderId),
    queryFn: () => fetchContainerStats(orderId),
    enabled: !!orderId && enabled,
    refetchInterval: 3000, // Refresh every 3 seconds
  })
}

/**
 * Fetch stats for a single container (faster refresh for detail view)
 */
export function useSingleContainerStats(
  orderId: string,
  containerId: string,
  enabled: boolean = true
) {
  return useQuery({
    queryKey: portainerKeys.singleContainerStats(orderId, containerId),
    queryFn: () => fetchSingleContainerStats(orderId, containerId),
    enabled: !!orderId && !!containerId && enabled,
    refetchInterval: 2000, // Refresh every 2 seconds for detail view
  })
}

/**
 * Container action mutation (start, stop, restart)
 */
export function useContainerAction() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async ({
      orderId,
      containerId,
      action,
    }: {
      orderId: string
      containerId: string
      action: 'start' | 'stop' | 'restart'
    }) => {
      const response = await fetch(
        `/api/v1/admin/orders/${orderId}/containers/${containerId}/${action}`,
        { method: 'POST' }
      )
      if (!response.ok) {
        const error = await response.json()
        throw new Error(error.error || `Failed to ${action} container`)
      }
      return response.json()
    },
    onSuccess: (_, { orderId }) => {
      queryClient.invalidateQueries({ queryKey: portainerKeys.containers(orderId) })
    },
  })
}

/**
 * Remove container mutation
 */
export function useRemoveContainer() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async ({
      orderId,
      containerId,
      force = false,
    }: {
      orderId: string
      containerId: string
      force?: boolean
    }) => {
      const response = await fetch(
        `/api/v1/admin/orders/${orderId}/containers/${containerId}?force=${force}`,
        { method: 'DELETE' }
      )
      if (!response.ok) {
        const error = await response.json()
        throw new Error(error.error || 'Failed to remove container')
      }
      return response.json()
    },
    onSuccess: (_, { orderId }) => {
      queryClient.invalidateQueries({ queryKey: portainerKeys.containers(orderId) })
    },
  })
}
