/**
 * Screenshot backend (safe, no ban risk, not real-time).
 *
 * Periodically grabs a frame from the VNC X display with ffmpeg's x11grab and
 * posts it to the invoking text channel. Low FPS, but works with a normal bot
 * account and never touches Discord's selfbot surface.
 */
import { spawn } from "node:child_process";
import type { AppConfig } from "../config.ts";
import type { ScreenStreamer, StreamContext } from "./index.ts";

function grabFrame(display: string, size: string): Promise<Buffer> {
  return new Promise((resolve, reject) => {
    const ff = spawn("ffmpeg", [
      "-loglevel", "error",
      "-f", "x11grab",
      "-video_size", size,
      "-i", display,
      "-frames:v", "1",
      "-f", "image2pipe",
      "-vcodec", "png",
      "pipe:1",
    ]);
    const chunks: Buffer[] = [];
    ff.stdout.on("data", (c) => chunks.push(c));
    ff.on("error", reject);
    ff.on("close", (code) =>
      code === 0 ? resolve(Buffer.concat(chunks)) : reject(new Error(`ffmpeg exited ${code}`)),
    );
  });
}

export class ScreenshotStreamer implements ScreenStreamer {
  readonly kind = "screenshot" as const;
  private timer: ReturnType<typeof setInterval> | null = null;
  constructor(private config: AppConfig) {}

  isActive() {
    return this.timer !== null;
  }

  async start(ctx: StreamContext): Promise<string> {
    if (!ctx.postImage) return "스크린샷을 올릴 텍스트 채널 컨텍스트가 없습니다.";
    if (this.timer) return "이미 스크린샷 송출 중입니다.";
    const tick = async () => {
      try {
        const png = await grabFrame(this.config.vncDisplay, this.config.vncResolution);
        await ctx.postImage!(png, "vnc.png");
      } catch (e) {
        console.error("[screenshot] grab failed:", e);
      }
    };
    this.timer = setInterval(tick, this.config.screenshotIntervalSec * 1000);
    void tick();
    return `📸 ${this.config.screenshotIntervalSec}초마다 VNC 스크린샷을 이 채널에 올립니다.`;
  }

  async stop(): Promise<void> {
    if (this.timer) clearInterval(this.timer);
    this.timer = null;
  }
}
