import { storage } from "./storage";
import type { InsertTranscription } from "@shared/schema";
import path from "path";
import fs from "fs";
import { spawn } from "child_process";
import axios from "axios";
import FormData from "form-data";
import { getRTMPUrl, isStreamActive, isRTMPServerRunning } from "./rtmp-server";

const TEMP_DIR = "uploads/transcription/";
const MAX_TEMP_FILE_AGE = 1000 * 60 * 5; // 5 minutes in milliseconds

// Track active transcription intervals by sessionId
export const transcriptionIntervals = new Map<number, NodeJS.Timeout>();

async function processStreamClip(sessionId: number): Promise<void> {
  let tempFilePath: string | null = null;

  try {
    console.log(`🎬 Starting stream clip processing for session ${sessionId}`);
    const processStartTime = Date.now();

    // Get transcription mode from settings
    const settings = await storage.getSettings();
    const mode = settings?.transcriptionMode || "test";
    console.log(`🔄 Running in ${mode} mode for session ${sessionId}`);

    let audioSource: string;
    if (mode === "test") {
      // Test mode: Use local file
      audioSource = path.join(process.cwd(), "uploads", "3.mp3");
      if (!fs.existsSync(audioSource)) {
        throw new Error("Test file '3.mp3' not found in uploads folder");
      }
      console.log("📁 Using test file:", audioSource);
    } else {
      // Live mode: Use RTMP stream
      audioSource = `rtmp://transcription.confapp.co/live/session_${sessionId}`;
      console.log("🎥 Using RTMP stream:", audioSource);
    }

    // Create session-specific directory
    const sessionDir = path.join(TEMP_DIR, `session_${sessionId}`);
    if (!fs.existsSync(sessionDir)) {
      fs.mkdirSync(sessionDir, { recursive: true });
    }

    // Convert the audio to WAV with correct parameters
    const timestamp = Date.now();
    const uniqueFileName = `clip_${timestamp}.wav`;
    tempFilePath = path.join(sessionDir, uniqueFileName);

    console.log(
      `🎙 Converting audio to WAV format for session ${sessionId}...`,
    );

    // Create a promise to handle the FFmpeg process
    await new Promise((resolve, reject) => {
      const ffmpegArgs = [
        "-re",
        "-probesize",
        "32",
        "-analyzeduration",
        "0",
        "-i",
        audioSource,
        "-t",
        "20",
        "-bufsize",
        "64k",
        "-acodec",
        "pcm_s16le",
        "-ac",
        "1",
        "-ar",
        "16000",
        "-y",
        tempFilePath,
      ];

      console.log("Executing FFmpeg with args:", ffmpegArgs.join(" "));

      const ffmpeg = spawn("ffmpeg", ffmpegArgs);
      let stdoutData = "";
      let stderrData = "";

      ffmpeg.stdout.on("data", (data) => {
        stdoutData += data.toString();
      });

      ffmpeg.stderr.on("data", (data) => {
        stderrData += data.toString();
        // Log progress but don't overwhelm the console
        if (stderrData.includes("time=")) {
          console.log("FFmpeg progress:", data.toString().trim());
        }
      });

      ffmpeg.on("close", (code) => {
        if (
          code === 0 &&
          fs.existsSync(tempFilePath) &&
          fs.statSync(tempFilePath).size > 0
        ) {
          console.log("✅ FFmpeg completed successfully");
          resolve(true);
        } else {
          console.error("FFmpeg failed with code:", code);
          console.error("FFmpeg stderr:", stderrData);
          reject(new Error(`FFmpeg failed with code ${code}`));
        }
      });

      ffmpeg.on("error", (err) => {
        console.error("FFmpeg spawn error:", err);
        reject(err);
      });

      // Set a timeout to kill the process if it takes too long
      setTimeout(() => {
        ffmpeg.kill();
        reject(new Error("FFmpeg process timed out after 25 seconds"));
      }, 25000);
    });

    // Get transcription from OpenAI Whisper
    const transcript = await transcribeWithOpenAI(tempFilePath);

    if (transcript) {
      // Translate to English with OpenAI
      const translation = await translateWithOpenAI(transcript);

      // Save to database
      const dbStartTime = Date.now();
      const transcriptionData: InsertTranscription = {
        sessionId,
        sourceLanguage: "Arabic",
        originalText: transcript,
        translatedText: translation,
        clipStartTime: new Date(Date.now() - 20000), // 20 seconds ago
        clipEndTime: new Date(),
        status: "pending",
      };

      await storage.createTranscription(transcriptionData);
      console.log(`⏱ Database save time: ${Date.now() - dbStartTime}ms`);
    }

    const totalProcessingTime = Date.now() - processStartTime;
    console.log(
      `⏱ Total processing time for session ${sessionId}: ${totalProcessingTime}ms`,
    );
  } catch (error) {
    console.error(
      `❌ Error processing stream clip for session ${sessionId}:`,
      error,
    );
    throw error;
  } finally {
    // Cleanup temp file
    if (tempFilePath && fs.existsSync(tempFilePath)) {
      try {
        fs.unlinkSync(tempFilePath);
        console.log(
          `🧹 Cleaned up temp file for session ${sessionId}: ${tempFilePath}`,
        );
      } catch (cleanupError) {
        console.error(
          `Failed to clean up temp file ${tempFilePath}:`,
          cleanupError,
        );
      }
    }
  }
}

// Ensure temp directory exists
if (!fs.existsSync(TEMP_DIR)) {
  fs.mkdirSync(TEMP_DIR, { recursive: true });
}

// Helper function to recursively remove directories and files
function removeOldFiles(dirPath: string, maxAge: number) {
  const now = Date.now();
  const items = fs.readdirSync(dirPath);

  items.forEach((item) => {
    const fullPath = path.join(dirPath, item);
    const stats = fs.statSync(fullPath);
    const fileAge = now - stats.mtimeMs;

    if (fileAge > maxAge) {
      if (stats.isDirectory()) {
        // Recursively clean directory contents first
        removeOldFiles(fullPath, maxAge);
        // Then remove the empty directory
        try {
          fs.rmdirSync(fullPath);
          console.log(`🧹 Cleaned up old directory: ${fullPath}`);
        } catch (error) {
          if (error.code !== "ENOTEMPTY") {
            console.error(`Failed to remove directory ${fullPath}:`, error);
          }
        }
      } else {
        // Remove file
        try {
          fs.unlinkSync(fullPath);
          console.log(`🧹 Cleaned up old file: ${fullPath}`);
        } catch (error) {
          console.error(`Failed to remove file ${fullPath}:`, error);
        }
      }
    }
  });
}

// Clean up old temporary files
function cleanupOldTempFiles() {
  try {
    if (!fs.existsSync(TEMP_DIR)) {
      return;
    }

    console.log("Starting cleanup of old temporary files...");
    removeOldFiles(TEMP_DIR, MAX_TEMP_FILE_AGE);
    console.log("Cleanup completed");
  } catch (error) {
    console.error("Error during cleanup:", error);
  }
}

// Run cleanup periodically
setInterval(cleanupOldTempFiles, MAX_TEMP_FILE_AGE);

async function transcribeWithOpenAI(audioFilePath: string): Promise<string> {
  try {
    console.log("🎙 Starting OpenAI Whisper transcription");
    const startTime = Date.now();

    const audioData = fs.createReadStream(audioFilePath);
    const formData = new FormData();
    formData.append("file", audioData, {
      filename: "audio.wav",
      contentType: "audio/wav",
    });
    formData.append("model", "whisper-1");
    formData.append("language", "ar");

    const response = await axios.post(
      "https://api.openai.com/v1/audio/transcriptions",
      formData,
      {
        headers: {
          ...formData.getHeaders(),
          Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
        },
      },
    );

    const endTime = Date.now();
    console.log(
      `⏱ OpenAI Whisper API response time: ${endTime - startTime}ms`,
    );

    if (!response.data.text) {
      throw new Error("No transcription text in response");
    }

    console.log("✅ Received transcript from OpenAI Whisper");
    return response.data.text;
  } catch (error: any) {
    console.error(
      "❌ OpenAI Whisper API Error:",
      error instanceof Error ? error.message : "Unknown error",
      error.response?.data,
    );
    throw error;
  }
}

async function translateWithOpenAI(text: string): Promise<string> {
  try {
    console.log("🤖 Starting OpenAI translation");
    const startTime = Date.now();
    const response = await axios.post(
      "https://api.openai.com/v1/chat/completions",
      {
        model: "gpt-4",
        messages: [
          {
            role: "system",
            content:
              "You are a professional translator. Translate the following Arabic text to English, maintaining the original meaning and context.",
          },
          {
            role: "user",
            content: text,
          },
        ],
      },
      {
        headers: {
          Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
          "Content-Type": "application/json",
        },
      },
    );
    const endTime = Date.now();
    console.log(`⏱ OpenAI API response time: ${endTime - startTime}ms`);

    const translation = response.data.choices[0].message.content;
    console.log("✅ Received translation from OpenAI");
    return translation;
  } catch (error: any) {
    console.error(
      "❌ OpenAI API Error:",
      error instanceof Error ? error.message : "Unknown error",
      error.response?.data,
    );
    throw error;
  }
}

export function startTranscriptionService(sessionId: number): void {
  console.log(`🚀 Starting transcription service for session: ${sessionId}`);

  // Stop existing transcription for this session if it exists
  if (transcriptionIntervals.has(sessionId)) {
    stopTranscriptionService(sessionId);
  }

  // Process immediately and then set up interval
  processStreamClip(sessionId).catch((error) => {
    console.error(
      `Failed to process stream clip for session ${sessionId}:`,
      error,
    );
  });

  // Set up interval for continuous processing (every 20 seconds)
  const interval = setInterval(() => {
    processStreamClip(sessionId).catch((error) => {
      console.error(
        `Failed to process stream clip for session ${sessionId}:`,
        error,
      );
    });
  }, 20000);

  transcriptionIntervals.set(sessionId, interval);
  console.log(`📝 Transcription service started for session ${sessionId}`);
}

export function stopTranscriptionService(sessionId?: number): void {
  if (sessionId) {
    // Stop specific session
    const interval = transcriptionIntervals.get(sessionId);
    if (interval) {
      clearInterval(interval);
      transcriptionIntervals.delete(sessionId);
      console.log(`⏹ Transcription service stopped for session ${sessionId}`);
    }
  } else {
    // Stop all sessions if no sessionId provided
    transcriptionIntervals.forEach((interval, id) => {
      clearInterval(interval);
      console.log(`⏹ Transcription service stopped for session ${id}`);
    });
    transcriptionIntervals.clear();
  }
}
