import request from '../utils/request'

const RAG_TIMEOUT = 0

const unwrap = (promise) => promise.then(response => response.data)

export function retrieveDocumentEvidence(query, topK = 5, mode = 'hybrid') {
  return unwrap(request.post('/rag/document/retrieve', { query, topK, filters: { mode } }, { timeout: RAG_TIMEOUT }))
}

export function retrieveStructuredEvidence(query, sourceIds, topK = 5) {
  return unwrap(request.post('/rag/structured/retrieve', {
    query, sourceIds, topK, filters: { allowTextToSql: true }
  }, { timeout: RAG_TIMEOUT }))
}

export function retrieveGraphEvidence(query, sourceIds, topK = 5) {
  return unwrap(request.post('/rag/graph/retrieve', {
    query, sourceIds, topK, filters: { allowTextToCypher: true }
  }, { timeout: RAG_TIMEOUT }))
}

export function retrieveKnowledgeBaseEvidence(params) {
  return unwrap(request.post('/rag/kb/retrieve', params, { timeout: RAG_TIMEOUT }))
}

export function getRagCapability(sourceType, sourceId) {
  return unwrap(request.get(`/rag/capabilities/${sourceType}/${sourceId}`))
}

export function refreshRagCapability(sourceType, sourceId) {
  return unwrap(request.post(`/rag/capabilities/${sourceType}/${sourceId}/refresh`))
}

export function suggestRagGovernance(sourceType, sourceId, description = '') {
  return unwrap(request.post(`/rag/capabilities/${sourceType}/${sourceId}/suggest`, { description }, { timeout: RAG_TIMEOUT }))
}

export function getGraphGovernance(sourceId) {
  return unwrap(request.get(`/rag/capabilities/GRAPH/${sourceId}/governance`))
}

export function updateGraphGovernance(sourceId, config) {
  return unwrap(request.put(`/rag/capabilities/GRAPH/${sourceId}/governance`, config))
}

export function getGraphReadiness(sourceId) {
  return unwrap(request.get(`/rag/capabilities/GRAPH/${sourceId}/readiness`))
}

export function listRagQueryExamples(sourceType, sourceId) {
  return unwrap(request.get(`/rag/capabilities/${sourceType}/${sourceId}/examples`))
}

export function addRagQueryExampleCandidates(sourceType, sourceId, candidates) {
  return unwrap(request.post(`/rag/capabilities/${sourceType}/${sourceId}/examples/candidates`, candidates))
}

export function verifyRagQueryExample(id, verified) {
  return unwrap(request.put(`/rag/capabilities/examples/${id}/verified`, null, { params: { value: verified } }))
}

export function deleteRagQueryExample(id) {
  return unwrap(request.delete(`/rag/capabilities/examples/${id}`))
}

export function getKnowledgeBaseBindings(knowledgeBaseId) {
  return unwrap(request.get(`/rag/kb/${knowledgeBaseId}/bindings`))
}

export function listKnowledgeBases() {
  return unwrap(request.get('/rag/kb'))
}

export function updateKnowledgeBaseBindingConfig(knowledgeBaseId, bindingId, config) {
  return unwrap(request.put(`/rag/kb/${knowledgeBaseId}/bindings/${bindingId}/config`, config))
}

export function upsertKnowledgeBaseBindingBySource(knowledgeBaseId, sourceType, sourceId, config) {
  return unwrap(request.put(`/rag/kb/${knowledgeBaseId}/bindings/by-source`, { sourceType, sourceId, config }))
}

export function generateRagAnswer(question, evidences) {
  return unwrap(request.post('/rag/answer', { question, evidences }, { timeout: RAG_TIMEOUT }))
}

export async function sendRagQuestion(params) {
  const { query, topK = 5, strategy = 'hybrid', enabled, structuredSourceIds = [], graphSourceIds = [], onStep } = params
  const results = { document: null, structured: null, graph: null, kb: null }
  const tasks = []

  if (enabled.document) {
    onStep?.('document', 'running')
    tasks.push(retrieveDocumentEvidence(query, topK, strategy)
      .then(data => { results.document = data; onStep?.('document', 'success', data) })
      .catch(error => { onStep?.('document', 'failed', null, error); results.document = { evidences: [], diagnostics: { error: error.message } } }))
  }

  if (enabled.structured) {
    onStep?.('structured', 'running')
    tasks.push(retrieveStructuredEvidence(query, structuredSourceIds, topK)
      .then(data => {
        results.structured = data
        const diagnostics = data?.diagnostics || {}
        const error = Object.keys(diagnostics).some(key => key === 'error')
          ? new Error(JSON.stringify(diagnostics)) : null
        onStep?.('structured', error ? 'failed' : 'success', data, error)
      })
      .catch(error => {
        onStep?.('structured', 'failed', null, error)
        results.structured = { evidences: [], diagnostics: { error: error.message } }
      }))
  }

  if (enabled.graph) {
    onStep?.('graph', 'running')
    tasks.push(retrieveGraphEvidence(query, graphSourceIds, topK)
      .then(data => {
        results.graph = data
        const diagnostics = data?.diagnostics || {}
        const error = Object.keys(diagnostics).length ? new Error(JSON.stringify(diagnostics)) : null
        onStep?.('graph', error ? 'failed' : 'success', data, error)
      })
      .catch(error => {
        onStep?.('graph', 'failed', null, error)
        results.graph = { evidences: [], diagnostics: { error: error.message } }
      }))
  }

  await Promise.all(tasks)
  const evidences = [results.document, results.structured, results.graph]
    .flatMap(result => result?.evidences || [])
  return { ...results, evidences }
}
