import { useGeneration } from './use-generation.tsrx'
import type { StreamChunk, TTSResult } from '@tanstack/ai'
import type {
  AIDevtoolsDisplayOptions,
  ConnectConnectionAdapter,
  GenerationClientState,
  GenerationFetcher,
  InferGenerationOutputFromReturn,
  SpeechGenerateInput,
} from '@tanstack/ai-client'

/**
 * Options for the useGenerateSpeech hook.
 *
 * @template TOutput - The output type after optional transform (defaults to TTSResult)
 */
export interface UseGenerateSpeechOptions<TOutput = TTSResult> {
  /** Connect-based adapter for streaming transport (SSE, HTTP stream, custom) */
  connection?: ConnectConnectionAdapter
  /** Direct async function for speech generation */
  fetcher?: GenerationFetcher<SpeechGenerateInput, TTSResult>
  /** Unique identifier for this generation instance */
  id?: string
  /** Additional body parameters to send with connect-based adapter requests */
  body?: Record<string, any>
  /** Display options for TanStack AI Devtools. */
  devtools?: AIDevtoolsDisplayOptions
  /**
   * Callback when speech is generated. Can optionally return a transformed value.
   *
   * - Return a non-null value to transform and store it as the result
   * - Return `null` to keep the previous result unchanged
   * - Return nothing (`void`) to store the raw result as-is
   */
  onResult?: (result: TTSResult) => TOutput | null | void
  /** Callback when an error occurs */
  onError?: (error: Error) => void
  /** Callback when progress is reported (0-100) */
  onProgress?: (progress: number, message?: string) => void
  /** Callback for each stream chunk (connect-based adapter mode only) */
  onChunk?: (chunk: StreamChunk) => void
}

/**
 * Return type for the useGenerateSpeech hook.
 *
 * @template TOutput - The output type (after optional transform)
 */
export interface UseGenerateSpeechReturn<TOutput = TTSResult> {
  /** Trigger speech generation */
  generate: (input: SpeechGenerateInput) => Promise<void>
  /** The TTS result containing audio data, or null */
  result: TOutput | null
  /** Whether generation is in progress */
  isLoading: boolean
  /** Current error, if any */
  error: Error | undefined
  /** Current state of the generation */
  status: GenerationClientState
  /** Abort the current generation */
  stop: () => void
  /** Clear result, error, and return to idle */
  reset: () => void
}

/**
 * Octane hook for generating speech (text-to-speech) using AI models.
 *
 * @example
 * ```tsx
 * import { useGenerateSpeech } from '@octanejs/tanstack-ai'
 * import { fetchServerSentEvents } from '@tanstack/ai-client'
 *
 * function SpeechGenerator() {
 *   const { generate, result, isLoading } = useGenerateSpeech({
 *     connection: fetchServerSentEvents('/api/generate/speech'),
 *   })
 *
 *   return (
 *     <div>
 *       <button onClick={() => generate({ text: 'Hello world', voice: 'alloy' })}>
 *         Generate Speech
 *       </button>
 *       {result && (
 *         <audio src={`data:audio/${result.format};base64,${result.audio}`} controls />
 *       )}
 *     </div>
 *   )
 * }
 * ```
 */
export function useGenerateSpeech<TTransformed = void>(
  options: Omit<UseGenerateSpeechOptions, 'onResult'> & {
    onResult?: (result: TTSResult) => TTransformed
  },
): UseGenerateSpeechReturn<
  InferGenerationOutputFromReturn<TTSResult, TTransformed>
> {
  const devtools = {
    ...options.devtools,
    // Octane divergence note.
    framework: 'octane',
    hookName: 'useGenerateSpeech',
    outputKind: 'audio' as const,
  }
  const { generate, result, isLoading, error, status, stop, reset } =
    useGeneration<SpeechGenerateInput, TTSResult, TTransformed>({
      ...options,
      devtools,
    })

  return {
    generate: generate as (input: SpeechGenerateInput) => Promise<void>,
    result,
    isLoading,
    error,
    status,
    stop,
    reset,
  }
}
