// -----------------------------
// app.js
// -----------------------------
const express = require('express');
const cors = require('cors');
const fs = require('fs');
const https = require('https');
const WebSocket = require('ws');
const dotenv = require('dotenv');

dotenv.config();

const app = express();

app.use(express.json({ limit: "200mb" }));
app.use(express.urlencoded({ extended: true, limit: "200mb" }));

// Add this new route for testing
app.get('/test', (req, res) => {
    console.log('[audiochat] Test route hit!');
    res.json({
        status: "success",
        message: "API is reachable!",
        timestamp: new Date().toISOString()
    });
});

// -----------------------------
// Helper: Logging
// -----------------------------
const log = (...args) => console.log('[audiochat]', ...args);

// -----------------------------
// Middleware
// -----------------------------
app.use(cors({ exposedHeaders: ["X-Final-Answer"] }));
app.use(express.json());

// -----------------------------
// SSL Options
// -----------------------------
/*
const sslOptions = {
  key: fs.readFileSync('/etc/letsencrypt/live/stream.ktono.com/privkey.pem'),
  cert: fs.readFileSync('/etc/letsencrypt/live/stream.ktono.com/fullchain.pem')
}; */

const sslOptions = {
  key: fs.readFileSync('./privkey.pem'),
  cert: fs.readFileSync('./fullchain.pem')
};

// -----------------------------
// Prompts
// -----------------------------
const COMBINED_PROMPT = `
    Before we proceed, I’d like to establish a few guidelines that will help both of us. Rule one: Hold off on questions until the concept is fully explained. You’ll have dedicated time afterward. Rule two: Always reply when I pose a question. This allows me to gauge your understanding and tailor future sessions. Rule three: Take structured notes as we go; it’ll boost retention and mastery. Rule four: dont ask questions that I havent taught yet. No questions will be entertained about course duration or remaining lectures. Completion depends entirely on your own pace. On average, students finish in 42 lectures—and yes, everything will be taught. now that you agree to the rules - You may now raise any questions about what we’ve covered so far.

    answer doubts related to this written above and scold on a light tone if anyone breaks the rules and ask irrelevant question..
`.trim();

const FALLBACK_TEXT = "No answer found";

const API_KEY = process.env.OPENAI_API_KEY;

// -----------------------------
// API Route
// -----------------------------

app.post('/ask', async (req, res) => {
    console.log("----------------------------");
    console.log("RECEIVED REQUEST AT /ASK");
    
    const { text, voice } = req.body;
    if (!text) return res.status(400).send("No question provided");

    let answered = false;

    async function askPrompt() {
        let answerText = "";
        const ws = new WebSocket(
            "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview",
            {
                headers: {
                    Authorization: `Bearer ${API_KEY}`,
                    "OpenAI-Beta": "realtime=v1",
                },
            }
        );

        const timeout = setTimeout(() => {
            if (!answered) {
                ws.close();
                sendTTS("The request timed out.");
            }
        }, 15000);

        ws.on('open', () => {
            ws.send(JSON.stringify({
                type: "conversation.item.create",
                item: {
                    type: "message",
                    role: "system",
                    content: [{ type: "input_text", text: COMBINED_PROMPT }],
                },
            }));

            ws.send(JSON.stringify({
                type: "conversation.item.create",
                item: {
                    type: "message",
                    role: "user",
                    content: [{ type: "input_text", text }],
                },
            }));

            ws.send(JSON.stringify({
                type: "response.create",
                response: { modalities: ["text"] },
            }));
        });

        ws.on('message', (data) => {
            const msg = JSON.parse(data.toString());

            if (msg.type === "response.text.delta") {
                answerText += msg.delta;
            }

            if (msg.type === "response.text.done" && !answered) {
                answered = true;
                clearTimeout(timeout);
                ws.close();
                sendTTS(answerText.trim() || "No answer found.");
            }

            // FIXED: Moved inside the message handler
            if (msg.type === "error") {
                console.error("OpenAI WS Error:", msg.error);
                answered = true;
                ws.close();
                sendTTS("There was an error processing your request.");
            }
        });

        ws.on('error', (err) => {
            clearTimeout(timeout);
            console.error("WS error:", err);
            if (!answered) sendTTS("Connection error.");
        });
    }

    async function sendTTS(textToSpeak) {
        try {
            console.log("Generating TTS for:", textToSpeak);
            const ttsResponse = await fetch("https://api.openai.com/v1/audio/speech", {
                method: "POST",
                headers: {
                    "Authorization": `Bearer ${API_KEY}`,
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({
                    model: "tts-1", 
                    voice: voice || "alloy",
                    input: textToSpeak,
                }),
            });

            if (!ttsResponse.ok) {
                const errorData = await ttsResponse.text();
                return res.status(500).send("OpenAI TTS failed: " + errorData);
            }

            const arrayBuffer = await ttsResponse.arrayBuffer();
            
            // FIXED: Actually sending the response back to the browser
            if (!res.headersSent) {
                res.setHeader("X-Final-Answer", encodeURIComponent(textToSpeak));
                res.setHeader("Content-Type", "audio/mpeg");
                res.send(Buffer.from(arrayBuffer)); 
            }
        } catch (err) {
            console.error("TTS Logic Error:", err);
            if (!res.headersSent) res.status(500).send("Internal Server Error");
        }
    }

    // Start the process
    askPrompt();
});



const IMG_PROMPT = `You must examine the uploaded image and verify whether the user has correctly circled February 2019. If the circle is missing or placed incorrectly, guide the user step-by-step to the precise location by giving helpful hints until they reach the right spot. When the user marks the correct area, respond with appreciation, and if a mistake is made, give soft corrective scolding in an encouraging and polite tone.`.trim();

app.post("/imagechat", async (req, res) => {
  try {
    const { imageBase64, voice } = req.body;
    if (!imageBase64) return res.status(400).send("No image provided");

    const cleanBase64 = imageBase64.replace(/^data:image\/\w+;base64,/, "");

    const ws = new WebSocket(
      "wss://api.openai.com/v1/realtime?model=gpt-realtime",
      {
        headers: {
          Authorization: `Bearer ${API_KEY}`,
          "OpenAI-Beta": "realtime=v1",
        },
      }
    );

    let description = "";
    let answered = false;

    ws.on("open", () => {
      ws.send(JSON.stringify({
        type: "conversation.item.create",
        item: {
          type: "message",
          role: "system",
          content: [
            { type: "input_text", text: IMG_PROMPT }
          ]
        }
      }));

      ws.send(JSON.stringify({
        type: "conversation.item.create",
        item: {
          type: "message",
          role: "user",
          content: [
            { 
              type: "input_text", 
              text: IMG_PROMPT 
            },
            { type: "input_image", image_url: `data:image/png;base64,${cleanBase64}` }
          ]
        }
      }));

      ws.send(JSON.stringify({
        type: "response.create",
        response: { modalities: ["text"] }
      }));
    });

    ws.on("message", (data) => {
      const msg = JSON.parse(data.toString());

      if (msg.type === "response.text.delta") {
        description += msg.delta;
      }

      if (msg.type === "response.text.done" && !answered) {
        answered = true;
        ws.close();
        sendTTS(description.trim() || "No description available");
      }
    });

    ws.on("error", (err) => {
      console.error("WS ERROR:", err);
      if (!answered) sendTTS("No description available");
    });

    ws.on("close", () => console.log("WS CLOSED"));

    async function sendTTS(textToSpeak) {
      try {
        const ttsResponse = await fetch("https://api.openai.com/v1/audio/speech", {
          method: "POST",
          headers: {
            Authorization: `Bearer ${API_KEY}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            model: "gpt-4o-mini-tts",
            voice: voice || "alloy",
            input: textToSpeak,
            format: "mp3"
          })
        });

        const audioBuffer = Buffer.from(await ttsResponse.arrayBuffer());
        if (!res.headersSent) {
          
          res.setHeader("X-Final-Answer", encodeURIComponent(textToSpeak));
          res.setHeader("Content-Type", "audio/mpeg");
          res.send(audioBuffer);
        }
      } catch (err) {
        console.error("TTS ERROR:", err);
        if (!res.headersSent) res.status(500).send("Error generating audio");
      }
    }

  } catch (err) {
    console.error(err);
    res.status(500).send("Error generating audio");
  }
});


// -----------------------------
// HTTPS Server
// -----------------------------

const PORT = 3000;
https.createServer(sslOptions, app).listen(PORT, '0.0.0.0', () => {
    console.log(`Secure server running at https://stream.ktono.com:${PORT}`);
});

