import { computed, toValue, type MaybeRefOrGetter } from 'vue'
import { useQuery } from '@tanstack/vue-query'
import type { components } from './generated/schema'
import { apiClient } from './client'
import { throwApiProblem } from './contracts'
import { queryKeys } from './queryClient'

export type DocFileDto = components['schemas']['DocFileInfo']
export type DocDetailDto = components['schemas']['DocFileContent']
export type MemoryFileDto = components['schemas']['MemoryFileInfo']
export type MemoryDetailDto = components['schemas']['MemoryFileContent']
export type MemorySearchResultDto =
  components['schemas']['MemorySearchResult']

async function requireData<T>(
  response: Response,
  data: T | undefined,
  error: unknown,
  fallback: string,
): Promise<T> {
  if (!response.ok || error || !data) {
    await throwApiProblem(response, fallback)
  }
  return data as T
}

export async function fetchDocs(
  agentId = 'iris',
  signal?: AbortSignal,
): Promise<DocFileDto[]> {
  const { data, error, response } = await apiClient.GET('/api/v1/docs', {
    params: { query: { agentId } },
    signal,
  })
  return requireData(
    response,
    data,
    error,
    'Dokumente konnten nicht geladen werden',
  )
}

export async function fetchDoc(
  path: string,
  agentId = 'iris',
  signal?: AbortSignal,
): Promise<DocDetailDto> {
  const { data, error, response } = await apiClient.GET(
    '/api/v1/docs/{path}',
    {
      params: {
        path: { path },
        query: { agentId },
      },
      signal,
    },
  )
  return requireData(
    response,
    data,
    error,
    'Dokument konnte nicht geladen werden',
  )
}

export async function fetchMemoryFiles(
  agentId = 'iris',
  signal?: AbortSignal,
): Promise<MemoryFileDto[]> {
  const { data, error, response } = await apiClient.GET('/api/v1/memory', {
    params: { query: { agentId } },
    signal,
  })
  return requireData(
    response,
    data,
    error,
    'Memory-Dateien konnten nicht geladen werden',
  )
}

export async function fetchMemoryFile(
  name: string,
  agentId = 'iris',
  signal?: AbortSignal,
): Promise<MemoryDetailDto> {
  const { data, error, response } = await apiClient.GET(
    '/api/v1/memory/{name}',
    {
      params: {
        path: { name },
        query: { agentId },
      },
      signal,
    },
  )
  return requireData(
    response,
    data,
    error,
    'Memory-Inhalt konnte nicht geladen werden',
  )
}

export async function fetchMemorySearch(
  query: string,
  agentId = 'iris',
  signal?: AbortSignal,
): Promise<MemorySearchResultDto[]> {
  const { data, error, response } = await apiClient.GET(
    '/api/v1/memory/search',
    {
      params: { query: { q: query, agentId } },
      signal,
    },
  )
  return requireData(
    response,
    data,
    error,
    'Memory-Suche ist fehlgeschlagen',
  )
}

export function useDocsQuery(
  agentId: MaybeRefOrGetter<string> = 'iris',
) {
  const resolvedAgentId = computed(() => toValue(agentId))
  return useQuery({
    queryKey: computed(() => queryKeys.docs(resolvedAgentId.value)),
    queryFn: ({ signal }) => fetchDocs(resolvedAgentId.value, signal),
  })
}

export function useDocQuery(
  path: MaybeRefOrGetter<string>,
  enabled: MaybeRefOrGetter<boolean> = true,
  agentId: MaybeRefOrGetter<string> = 'iris',
) {
  const resolvedPath = computed(() => toValue(path))
  const resolvedAgentId = computed(() => toValue(agentId))
  return useQuery({
    queryKey: computed(() =>
      queryKeys.doc(resolvedAgentId.value, resolvedPath.value),
    ),
    queryFn: ({ signal }) =>
      fetchDoc(resolvedPath.value, resolvedAgentId.value, signal),
    enabled: computed(() => Boolean(resolvedPath.value) && toValue(enabled)),
  })
}

export function useMemoryFilesQuery(
  agentId: MaybeRefOrGetter<string> = 'iris',
) {
  const resolvedAgentId = computed(() => toValue(agentId))
  return useQuery({
    queryKey: computed(() => queryKeys.memory(resolvedAgentId.value)),
    queryFn: ({ signal }) => fetchMemoryFiles(resolvedAgentId.value, signal),
  })
}

export function useMemoryFileQuery(
  name: MaybeRefOrGetter<string>,
  enabled: MaybeRefOrGetter<boolean> = true,
  agentId: MaybeRefOrGetter<string> = 'iris',
) {
  const resolvedName = computed(() => toValue(name))
  const resolvedAgentId = computed(() => toValue(agentId))
  return useQuery({
    queryKey: computed(() =>
      queryKeys.memoryFile(resolvedAgentId.value, resolvedName.value),
    ),
    queryFn: ({ signal }) =>
      fetchMemoryFile(resolvedName.value, resolvedAgentId.value, signal),
    enabled: computed(() => Boolean(resolvedName.value) && toValue(enabled)),
  })
}

export function useMemorySearchQuery(
  search: MaybeRefOrGetter<string>,
  enabled: MaybeRefOrGetter<boolean> = true,
  agentId: MaybeRefOrGetter<string> = 'iris',
) {
  const resolvedSearch = computed(() => toValue(search).trim())
  const resolvedAgentId = computed(() => toValue(agentId))
  return useQuery({
    queryKey: computed(() =>
      queryKeys.memorySearch(resolvedAgentId.value, resolvedSearch.value),
    ),
    queryFn: ({ signal }) =>
      fetchMemorySearch(resolvedSearch.value, resolvedAgentId.value, signal),
    enabled: computed(() => resolvedSearch.value.length >= 2 && toValue(enabled)),
  })
}
