import { nanoRemix } from "@workshop/nano-remix"
import { OpenAI } from "openai"
import { Agent, run, webSearchTool, type AgentInputItem } from "@openai/agents"
import fs from "node:fs"
import { getErrorMessage } from "@workshop/shared/errors"
import { tools } from "./tools"

const server = Bun.serve({
  port: process.env.PORT || 3000,
  hostname: "0.0.0.0", // Accept connections from any IP
  tls: {
    key: Bun.file("certs/key.pem"),
    cert: Bun.file("certs/cert.pem"),
  },
  routes: {
    "/api/streamResponse": async (req) => {
      try {
        return streamResponse(req)
      } catch (error) {
        console.error("Transcription error:", error)
        return new Response(`Transcription failed: ${getErrorMessage(error)}`, { status: 500 })
      }
    },
    "/*": (req) => {
      return nanoRemix(req)
    },
  },
})

console.log(`Whiteboard running at ${server.url}:${server.port}`)

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
})

const streamResponse = async (req: Request) => {
  const transcript = await transcribeAudio(req)

  const agent = new Agent({
    name: "Whiteboard Assistant",
    model: "gpt-4o",
    instructions: `You are a helpful assistant that talks about an image.
You will receive a transcript of a conversation and an image. Your task is to analyze the transcript and the image, then generate a response that includes text and optional overlays on the image.

The overlays are a string description of what you would overlay on the image.
`,
    tools: [...tools, webSearchTool()],
  })

  const imagePath = "public/whiteboard.png"
  const base64Image = fs.readFileSync(imagePath, "base64")
  const input: AgentInputItem[] = [
    {
      role: "user",
      type: "message",
      content: [
        { type: "input_image", image: `data:image/png;base64,${base64Image}` },
        { type: "input_text", text: transcript },
      ],
    },
  ]

  const result = await run(agent, input, { stream: true })

  const customStream = new ReadableStream({
    async start(controller) {
      try {
        for await (const chunk of result) {
          if (chunk.type === "raw_model_stream_event" && chunk.data?.type === "output_text_delta") {
            const event = {
              type: "text_delta",
              data: chunk.data.delta,
            }
            controller.enqueue(`data: ${JSON.stringify(event)}\n\n`)
          }

          if (chunk.type === "run_item_stream_event" && chunk.item?.type === "tool_call_output_item") {
            const event = {
              type: "tool_output",
              data: chunk.item?.output,
            }
            controller.enqueue(`data: ${JSON.stringify(event)}\n\n`)
          }
        }

        controller.close()
      } catch (error) {
        controller.error(error)
      }
    },
  })

  return new Response(customStream, {
    headers: {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      Connection: "keep-alive",
      "Access-Control-Allow-Origin": "*",
    },
  })
}

const transcribeAudio = async (req: Request) => {
  if (req.method !== "POST") {
    throw new Error("Method not allowed, only POST is supported")
  } else if (!req.body) {
    throw new Error("No audio data provided")
  }

  const response = new Response(req.body)
  const audioBlob = await response.blob()
  const audioFile = new File([audioBlob], "audio.webm", { type: "audio/webm" })

  const transcript = await openai.audio.transcriptions.create({
    file: audioFile,
    model: "gpt-4o-mini-transcribe",
    response_format: "text",
  })

  return transcript
}
