import { get, post } from './client'
import type {
  AiEditRequest,
  EditorParseRequest,
  EditorParseResponse,
  EditorRepo,
  EditorSavePRRequest,
  EditorSavePRResponse,
  EditorSaveRequest,
  EditorSaveResponse,
  GenerateSpecRequest,
} from './types'

export function fetchEditorRepos(org: string): Promise<EditorRepo[]> {
  return get<EditorRepo[]>(`/app/${org}/editor/repos`)
}

export function fetchEditorFile(org: string, owner: string, repo: string, path: string): Promise<{ content: string; sha: string }> {
  return get<{ content: string; sha: string }>(`/app/${org}/editor/${owner}/${repo}/${path}/json`)
}

export function saveSpec(org: string, owner: string, repo: string, path: string, data: EditorSaveRequest): Promise<EditorSaveResponse> {
  return post<EditorSaveResponse>(`/app/${org}/editor/${owner}/${repo}/${path}/save`, data)
}

export function saveSpecAsPR(org: string, owner: string, repo: string, path: string, data: EditorSavePRRequest): Promise<EditorSavePRResponse> {
  return post<EditorSavePRResponse>(`/app/${org}/editor/${owner}/${repo}/${path}/save-pr`, data)
}

export function parseSpec(org: string, owner: string, repo: string, data: EditorParseRequest): Promise<EditorParseResponse> {
  return post<EditorParseResponse>(`/app/${org}/editor/${owner}/${repo}/parse`, data)
}

export function previewSpec(org: string, owner: string, repo: string, data: { content: string }): Promise<{ html: string }> {
  return post<{ html: string }>(`/app/${org}/editor/${owner}/${repo}/preview`, data)
}

export function fetchNewSpecTemplate(org: string, owner: string, repo: string): Promise<{ content: string }> {
  return get<{ content: string }>(`/app/${org}/editor/${owner}/${repo}/new/template`)
}

export async function generateSpecStream(
  org: string,
  owner: string,
  repo: string,
  data: GenerateSpecRequest,
  onChunk: (text: string) => void,
  onDone: () => void,
  onError: (error: string) => void,
): Promise<void> {
  const res = await fetch(`/app/${org}/editor/${owner}/${repo}/generate`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  })

  if (!res.ok) {
    const body = await res.json().catch(() => ({ error: `HTTP ${res.status}` }))
    onError(body.error ?? `Generation failed (${res.status})`)
    return
  }

  const reader = res.body?.getReader()
  if (!reader) {
    onError('No response stream')
    return
  }

  const decoder = new TextDecoder()
  let buffer = ''

  while (true) {
    const { done, value } = await reader.read()
    if (done) break

    buffer += decoder.decode(value, { stream: true })
    const lines = buffer.split('\n')
    buffer = lines.pop() ?? ''

    for (const line of lines) {
      if (!line.startsWith('data: ')) continue
      try {
        const payload = JSON.parse(line.slice(6))
        if (payload.done) {
          onDone()
          return
        }
        if (payload.error) {
          onError(payload.error)
          return
        }
        if (payload.chunk) {
          onChunk(payload.chunk)
        }
      } catch {
        // skip malformed lines
      }
    }
  }

  onDone()
}

export async function aiEditStream(
  org: string,
  owner: string,
  repo: string,
  data: AiEditRequest,
  onChunk: (text: string) => void,
  onDone: () => void,
  onError: (error: string) => void,
): Promise<void> {
  const res = await fetch(`/app/${org}/editor/${owner}/${repo}/ai-edit`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  })

  if (!res.ok) {
    const body = await res.json().catch(() => ({ error: `HTTP ${res.status}` }))
    onError(body.error ?? `AI edit failed (${res.status})`)
    return
  }

  const reader = res.body?.getReader()
  if (!reader) {
    onError('No response stream')
    return
  }

  const decoder = new TextDecoder()
  let buffer = ''

  while (true) {
    const { done, value } = await reader.read()
    if (done) break

    buffer += decoder.decode(value, { stream: true })
    const lines = buffer.split('\n')
    buffer = lines.pop() ?? ''

    for (const line of lines) {
      if (!line.startsWith('data: ')) continue
      try {
        const payload = JSON.parse(line.slice(6))
        if (payload.done) {
          onDone()
          return
        }
        if (payload.error) {
          onError(payload.error)
          return
        }
        if (payload.chunk) {
          onChunk(payload.chunk)
        }
      } catch {
        // skip malformed lines
      }
    }
  }

  onDone()
}
