/**
 * React Hook for Cloudflare KV Operations
 * 
 * This hook provides a convenient way to interact with Cloudflare KV
 * from React components with loading states and error handling.
 */

import { useState, useCallback, useEffect } from 'react'
import { cloudflareKV, CloudflareKVClient } from '../utils/cloudflareKV'

interface UseCloudflareKVOptions {
  client?: CloudflareKVClient
}

interface KVOperationState<T = any> {
  data: T | null
  loading: boolean
  error: string | null
}

export function useCloudflareKV(options: UseCloudflareKVOptions = {}) {
  const client = options.client || cloudflareKV
  
  // State for get operations
  const [getState, setGetState] = useState<KVOperationState>({
    data: null,
    loading: false,
    error: null
  })

  // State for put operations
  const [putState, setPutState] = useState<KVOperationState>({
    data: null,
    loading: false,
    error: null
  })

  // State for delete operations
  const [deleteState, setDeleteState] = useState<KVOperationState>({
    data: null,
    loading: false,
    error: null
  })

  // State for list operations
  const [listState, setListState] = useState<KVOperationState>({
    data: null,
    loading: false,
    error: null
  })

  /**
   * Get a value from KV store
   */
  const get = useCallback(async <T = any>(key: string, parseJSON: boolean = true): Promise<T | string | null> => {
    setGetState({ data: null, loading: true, error: null })
    
    try {
      const result = await client.get<T>(key, parseJSON)
      setGetState({ data: result, loading: false, error: null })
      return result
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error'
      setGetState({ data: null, loading: false, error: errorMessage })
      throw error
    }
  }, [client])

  /**
   * Put a value to KV store
   */
  const put = useCallback(async (key: string, value: any, metadata?: Record<string, any>) => {
    setPutState({ data: null, loading: true, error: null })
    
    try {
      const result = await client.put(key, value, metadata)
      setPutState({ data: result, loading: false, error: null })
      return result
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error'
      setPutState({ data: null, loading: false, error: errorMessage })
      throw error
    }
  }, [client])

  /**
   * Delete a key from KV store
   */
  const deleteKey = useCallback(async (key: string) => {
    setDeleteState({ data: null, loading: true, error: null })
    
    try {
      const result = await client.delete(key)
      setDeleteState({ data: result, loading: false, error: null })
      return result
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error'
      setDeleteState({ data: null, loading: false, error: errorMessage })
      throw error
    }
  }, [client])

  /**
   * List keys from KV store
   */
  const listKeys = useCallback(async (prefix?: string, limit: number = 1000, cursor?: string) => {
    setListState({ data: null, loading: true, error: null })
    
    try {
      const result = await client.listKeys(prefix, limit, cursor)
      setListState({ data: result, loading: false, error: null })
      return result
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error'
      setListState({ data: null, loading: false, error: errorMessage })
      throw error
    }
  }, [client])

  /**
   * Check if a key exists
   */
  const exists = useCallback(async (key: string): Promise<boolean> => {
    try {
      return await client.exists(key)
    } catch (error) {
      console.error('Error checking key existence:', error)
      return false
    }
  }, [client])

  /**
   * Put multiple values in batch
   */
  const putBatch = useCallback(async (entries: Array<{ key: string; value: any; metadata?: Record<string, any> }>) => {
    setPutState({ data: null, loading: true, error: null })
    
    try {
      const result = await client.putBatch(entries)
      setPutState({ data: result, loading: false, error: null })
      return result
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error'
      setPutState({ data: null, loading: false, error: errorMessage })
      throw error
    }
  }, [client])

  /**
   * Clear all operation states
   */
  const clearStates = useCallback(() => {
    setGetState({ data: null, loading: false, error: null })
    setPutState({ data: null, loading: false, error: null })
    setDeleteState({ data: null, loading: false, error: null })
    setListState({ data: null, loading: false, error: null })
  }, [])

  return {
    // Operations
    get,
    put,
    delete: deleteKey,
    listKeys,
    exists,
    putBatch,
    clearStates,
    
    // States
    getState,
    putState,
    deleteState,
    listState,
    
    // Convenience getters
    isLoading: getState.loading || putState.loading || deleteState.loading || listState.loading,
    hasError: !!(getState.error || putState.error || deleteState.error || listState.error),
    errors: {
      get: getState.error,
      put: putState.error,
      delete: deleteState.error,
      list: listState.error
    }
  }
}

/**
 * Hook for managing a specific KV key with automatic loading and caching
 */
export function useKVValue<T = any>(key: string, parseJSON: boolean = true, autoLoad: boolean = true) {
  const [value, setValue] = useState<T | string | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [lastUpdated, setLastUpdated] = useState<Date | null>(null)

  const kv = useCloudflareKV()

  /**
   * Load the value from KV
   */
  const load = useCallback(async () => {
    if (!key) return

    setLoading(true)
    setError(null)

    try {
      const result = await kv.get<T>(key, parseJSON)
      setValue(result)
      setLastUpdated(new Date())
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Failed to load value'
      setError(errorMessage)
    } finally {
      setLoading(false)
    }
  }, [key, parseJSON, kv])

  /**
   * Save a new value to KV
   */
  const save = useCallback(async (newValue: T | string, metadata?: Record<string, any>) => {
    if (!key) return

    setLoading(true)
    setError(null)

    try {
      await kv.put(key, newValue, metadata)
      setValue(newValue)
      setLastUpdated(new Date())
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Failed to save value'
      setError(errorMessage)
      throw err
    } finally {
      setLoading(false)
    }
  }, [key, kv])

  /**
   * Delete the value from KV
   */
  const remove = useCallback(async () => {
    if (!key) return

    setLoading(true)
    setError(null)

    try {
      await kv.delete(key)
      setValue(null)
      setLastUpdated(new Date())
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Failed to delete value'
      setError(errorMessage)
      throw err
    } finally {
      setLoading(false)
    }
  }, [key, kv])

  /**
   * Refresh the value from KV
   */
  const refresh = useCallback(() => {
    return load()
  }, [load])

  // Auto-load on mount if enabled
  useEffect(() => {
    if (autoLoad && key) {
      load()
    }
  }, [autoLoad, key, load])

  return {
    value,
    loading,
    error,
    lastUpdated,
    load,
    save,
    remove,
    refresh,
    exists: value !== null
  }
}

// Export types
export type { KVOperationState }
