"use client";

import { api } from "@/convex/_generated/api";
import { Id } from "@/convex/_generated/dataModel";
import { Game } from "@/lib/types";
import { usePaginatedQuery } from "convex/react";
import Link from "next/link";
import { useEffect, useMemo, useRef, useState } from "react";
import { AuthGate } from "@/components/AuthGate";
import { useScreenRecorder } from "@/lib/useScreenRecorder";
import { uploadToSunoAndGenerateCovers, STYLE_PRESETS } from "@/lib/sunoApi";

// Lightweight IntersectionObserver hook
function useInView(callback: () => void) {
  const ref = useRef<HTMLDivElement | null>(null);
  useEffect(() => {
    if (!ref.current) return;
    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => {
          if (e.isIntersecting) callback();
        });
      },
      { rootMargin: "600px" }
    ); // prefetch ahead
    observer.observe(ref.current);
    return () => observer.disconnect();
  }, [callback]);
  return ref;
}

function GameCard({ game }: { game: Game }) {
  const {
    recordingState,
    recordedVideoUrl,
    startRecording,
    stopRecording,
    clearRecording,
    error: recordingError,
  } = useScreenRecorder();

  const [selectedStyle, setSelectedStyle] = useState<string>("relaxing");
  const [isGeneratingSuno, setIsGeneratingSuno] = useState(false);
  const [generatedCovers, setGeneratedCovers] = useState<string[]>([]);
  const [sunoError, setSunoError] = useState<string | null>(null);

  const iframeRef = useRef<HTMLIFrameElement>(null);
  const src = game.runtime === "external" ? game.srcUrl : game.srcUrl; // both resolve to an absolute or app-relative path

  const handleStartRecording = () => {
    if (iframeRef.current) {
      startRecording(iframeRef.current);
    } else {
      startRecording();
    }
  };

  // Extract audio from video
  const extractAudioFromVideo = async (videoUrl: string): Promise<Blob> => {
    return new Promise((resolve, reject) => {
      const video = document.createElement('video');
      video.src = videoUrl;
      video.crossOrigin = 'anonymous';

      video.addEventListener('loadedmetadata', async () => {
        try {
          // Create audio context
          const audioContext = new AudioContext();

          // Create media element source
          const source = audioContext.createMediaElementSource(video);

          // Create destination for recording
          const destination = audioContext.createMediaStreamDestination();
          source.connect(destination);

          // Create MediaRecorder for audio
          const mediaRecorder = new MediaRecorder(destination.stream, {
            mimeType: 'audio/webm',
          });

          const chunks: Blob[] = [];

          mediaRecorder.ondataavailable = (e) => {
            if (e.data.size > 0) {
              chunks.push(e.data);
            }
          };

          mediaRecorder.onstop = () => {
            const audioBlob = new Blob(chunks, { type: 'audio/webm' });
            resolve(audioBlob);
          };

          // Start recording and play video
          mediaRecorder.start();
          video.play();

          // Stop when video ends
          video.addEventListener('ended', () => {
            mediaRecorder.stop();
            audioContext.close();
          });
        } catch (err) {
          reject(err);
        }
      });

      video.addEventListener('error', reject);
    });
  };

  const handleGenerateCovers = async () => {
    if (!recordedVideoUrl) return;

    setIsGeneratingSuno(true);
    setSunoError(null);
    setGeneratedCovers([]);

    try {
      console.log('🎵 Extracting audio from video...');
      const audioBlob = await extractAudioFromVideo(recordedVideoUrl);
      console.log('✅ Audio extracted:', audioBlob.size, 'bytes');

      // Get the style string from the preset
      const styleString = STYLE_PRESETS[selectedStyle as keyof typeof STYLE_PRESETS];

      // Upload to Suno and generate covers
      const result = await uploadToSunoAndGenerateCovers(audioBlob, styleString);

      if (result.success && result.data) {
        // Extract audio URLs from the cover_clips array
        const audioUrls = result.data.cover_clips?.map((clip: any) => clip.audio_url).filter(Boolean) || [];
        setGeneratedCovers(audioUrls);
      } else {
        setSunoError(result.error || 'Failed to generate covers');
      }
    } catch (err) {
      setSunoError(err instanceof Error ? err.message : 'Unknown error occurred');
      console.error('Error generating covers:', err);
    } finally {
      setIsGeneratingSuno(false);
    }
  };

  // Sandbox hardening: disable top-nav, allow only what minigames need
  const sandbox = [
    "allow-scripts",
    "allow-same-origin",
    "allow-pointer-lock",
    "allow-popups-to-escape-sandbox",
  ].join(" ");

  return (
    <article className="mx-auto w-full max-w-sm md:max-w-md lg:max-w-lg rounded-2xl shadow p-3 md:p-4 bg-white dark:bg-zinc-900">
      <div className="flex gap-3 items-center mb-3">
        {game.coverUrl && (
          // eslint-disable-next-line @next/next/no-img-element
          <img
            src={game.coverUrl}
            alt={game.title}
            className="h-14 w-14 md:h-16 md:w-16 rounded-xl object-cover"
          />
        )}
        <div className="flex-1 min-w-0">
          <h3 className="text-lg md:text-xl font-semibold truncate">
            {game.title}
          </h3>
          <p className="text-sm md:text-base text-zinc-500 line-clamp-2">
            {game.description}
          </p>
        </div>
        <Link
          href={`/game/${game.slug}`}
          className="text-sm md:text-base underline opacity-80 hover:opacity-100"
        >
          Open
        </Link>
      </div>

      {/* Screen Recording Controls */}
      <div className="space-y-2">
        <div className="flex gap-2 items-center flex-wrap">
          {recordingState === 'idle' && (
            <>
              <button
                onClick={handleStartRecording}
                className="px-3 py-1.5 text-sm rounded-lg font-medium bg-red-500 hover:bg-red-600 text-white transition-all"
              >
                🎥 Record Game
              </button>
              <span className="text-xs text-zinc-500">
                (Check &quot;Share tab audio&quot; in browser dialog)
              </span>
            </>
          )}
          {recordingState === 'recording' && (
            <>
              <button
                onClick={stopRecording}
                className="px-3 py-1.5 text-sm rounded-lg font-medium bg-red-600 hover:bg-red-700 text-white animate-pulse transition-all"
              >
                ⏹ Stop Recording
              </button>
              <span className="text-xs text-red-500 animate-pulse">● Recording...</span>
            </>
          )}
          {recordingState === 'recorded' && (
            <>
              <button
                onClick={clearRecording}
                className="px-3 py-1.5 text-sm rounded-lg font-medium bg-gray-700 hover:bg-gray-600 text-white transition-all"
              >
                🗑 Clear Video
              </button>
              <button
                onClick={handleStartRecording}
                className="px-3 py-1.5 text-sm rounded-lg font-medium bg-red-500 hover:bg-red-600 text-white transition-all"
              >
                🎥 Record Again
              </button>
            </>
          )}
        </div>
      </div>

      {recordingError && (
        <div className="bg-red-500/20 border border-red-500 rounded-lg p-2 text-sm text-red-300">
          {recordingError}
        </div>
      )}

      <div className="relative w-full h-[500px] sm:h-[600px] md:h-[700px] lg:h-[800px] overflow-hidden rounded-xl border border-zinc-200 dark:border-zinc-800">
        <iframe
          ref={iframeRef}
          title={game.title}
          src={src}
          className="w-full h-full"
          loading="lazy"
          referrerPolicy="no-referrer"
          sandbox={sandbox}
          allow="gamepad *; accelerometer *; autoplay *; midi *; clipboard-read *; clipboard-write *"
        />
      </div>

      {/* Recorded Video Display */}
      {recordedVideoUrl && (
        <div className="mt-4 p-4 bg-black/40 backdrop-blur-sm rounded-xl border border-zinc-200 dark:border-zinc-800 space-y-4">
          <div>
            <h4 className="text-sm font-semibold mb-2">📹 Recorded Video</h4>
            <video
              controls
              src={recordedVideoUrl}
              className="w-full rounded-lg"
            />
          </div>

          {/* Suno Cover Generation */}
          <div className="border-t border-zinc-700 pt-4">
            <h4 className="text-sm font-semibold mb-3">🎵 Generate AI Covers with Suno</h4>

            <div className="flex flex-col gap-3">
              <div className="flex gap-2 items-center flex-wrap">
                <select
                  value={selectedStyle}
                  onChange={(e) => setSelectedStyle(e.target.value)}
                  disabled={isGeneratingSuno}
                  className="flex-1 min-w-[150px] px-3 py-2 text-sm rounded-lg bg-gray-800 text-white border border-gray-600 focus:border-purple-500 focus:outline-none disabled:opacity-50"
                >
                  {Object.keys(STYLE_PRESETS).map((style) => (
                    <option key={style} value={style}>
                      {style.charAt(0).toUpperCase() + style.slice(1)}
                    </option>
                  ))}
                </select>

                <button
                  onClick={handleGenerateCovers}
                  disabled={isGeneratingSuno}
                  className="px-4 py-2 text-sm rounded-lg font-medium bg-purple-600 hover:bg-purple-700 disabled:bg-gray-600 disabled:cursor-not-allowed text-white transition-all"
                >
                  {isGeneratingSuno ? '⏳ Generating...' : '✨ Generate Covers'}
                </button>
              </div>

              {sunoError && (
                <div className="bg-red-500/20 border border-red-500 rounded-lg p-2 text-xs text-red-300">
                  ❌ {sunoError}
                </div>
              )}

              {isGeneratingSuno && (
                <div className="flex items-center gap-2 bg-purple-500/20 backdrop-blur-sm px-3 py-2 rounded-lg border border-purple-500">
                  <div className="w-2 h-2 bg-purple-500 rounded-full animate-pulse" />
                  <span className="text-white text-xs">Generating AI covers...</span>
                </div>
              )}

              {generatedCovers.length > 0 && (
                <div className="space-y-2">
                  <p className="text-white text-xs font-semibold">Generated Covers:</p>
                  {generatedCovers.map((url, index) => (
                    <div key={index} className="bg-gray-800/50 p-2 rounded-lg">
                      <p className="text-white text-xs mb-1">Cover {index + 1}</p>
                      <audio
                        controls
                        src={url}
                        className="w-full h-8"
                      />
                    </div>
                  ))}
                </div>
              )}
            </div>
          </div>
        </div>
      )}

      <div className="flex gap-4 mt-3 text-sm md:text-base text-zinc-500">
        <span>{game.plays} plays</span>
        <span>{game.likes} likes</span>
      </div>
    </article>
  );
}

export default function HomePage() {
  const pageSize = 6;
  const { results, status, loadMore } = usePaginatedQuery(
    api.games.listGames,
    {},
    { initialNumItems: pageSize }
  );

  // Track client-side mount to ensure correct URLs
  const [isClient, setIsClient] = useState(false);

  useEffect(() => {
    setIsClient(true);
  }, []);

  // Inject test games for development
  const gamesWithTest = useMemo(() => {
    // Build base URL from current hostname and port
    // Only use window.location on client side after mount
    const baseUrl = isClient
      ? `${window.location.protocol}//${window.location.hostname}${
          window.location.port ? `:${window.location.port}` : ""
        }`
      : "";

    console.log("baseUrl:", baseUrl, "isClient:", isClient);

    // Don't inject test games during SSR
    if (!isClient) {
      return results || [];
    }

    const drumPad: Game = {
      _id: "drum-pad-id" as Id<"games">,
      title: "Drum Pad",
      slug: "drum-pad",
      description:
        "Record and play back your drum beats! Press Q-W-E-R-A-S-D-F to play drums, SPACE to record.",
      coverUrl:
        "https://images.unsplash.com/photo-1519892300165-cb5542fb47c7?w=400&h=400&fit=crop",
      runtime: "external",
      srcUrl: `${baseUrl}/games-test/drum-pad`,
      tags: ["drums", "recording", "interactive"],
      creatorId: "test-creator" as Id<"creators">,
      visibility: "public",
      publishedAt: Date.now() + 2000, // Sort first
      plays: 0,
      likes: 0,
      _creationTime: Date.now() + 2000,
    };

    const pianoTest: Game = {
      _id: "test-game-id" as Id<"games">,
      title: "Piano Player (Test)",
      slug: "piano-test",
      description: "A 2-octave piano player - click the keys to play music!",
      coverUrl:
        "https://images.unsplash.com/photo-1520523839897-bd0b52f945a0?w=400&h=400&fit=crop",
      runtime: "external",
      srcUrl: `${baseUrl}/games-test`,
      tags: ["piano", "music", "test"],
      creatorId: "test-creator" as Id<"creators">,
      visibility: "public",
      publishedAt: Date.now() + 1000,
      plays: 0,
      likes: 0,
      _creationTime: Date.now() + 1000,
    };

    const synthBox: Game = {
      _id: "synth-box-id" as Id<"games">,
      title: "Synth Box",
      slug: "synth-box",
      description:
        "Drag the box around to control a synthesizer! Y-axis = pitch, X-axis = filter.",
      coverUrl:
        "https://images.unsplash.com/photo-1598488035139-bdbb2231ce04?w=400&h=400&fit=crop",
      runtime: "external",
      srcUrl: `${baseUrl}/games-test/synth-box`,
      tags: ["synth", "interactive", "experimental"],
      creatorId: "test-creator" as Id<"creators">,
      visibility: "public",
      publishedAt: Date.now(),
      plays: 0,
      likes: 0,
      _creationTime: Date.now(),
    };

    const drumSequencer: Game = {
      _id: "drum-sequencer-id" as Id<"games">,
      title: "Drum Sequencer",
      slug: "drum-sequencer",
      description:
        "Create drum patterns with an 8-track sequencer! Press Q-W-E-R-A-S-D-F to play different drums.",
      coverUrl:
        "https://images.unsplash.com/photo-1571327073757-71d13c24de30?w=400&h=400&fit=crop",
      runtime: "external",
      srcUrl: `${baseUrl}/games-test/drum-sequencer`,
      tags: ["drums", "sequencer", "rhythm"],
      creatorId: "test-creator" as Id<"creators">,
      visibility: "public",
      publishedAt: Date.now() - 500,
      plays: 0,
      likes: 0,
      _creationTime: Date.now() - 500,
    };

    const tonysTunes: Game = {
      _id: "tonys-tunes-id" as Id<"games">,
      title: "Tony's Tunes",
      slug: "tonys-tunes",
      description: "An interactive music experience from Tony!",
      coverUrl:
        "https://images.unsplash.com/photo-1511379938547-c1f69419868d?w=400&h=400&fit=crop",
      runtime: "external",
      srcUrl:
        "https://suno-ai--hackathon-server-martin-dev-fastapi-app-dev.modal.run/ttunes/",
      tags: ["music", "interactive", "featured"],
      creatorId: "tony-creator" as Id<"creators">,
      visibility: "public",
      publishedAt: Date.now() - 1000, // Sort last
      plays: 0,
      likes: 0,
      _creationTime: Date.now() - 1000,
    };

    return results
      ? [drumPad, pianoTest, synthBox, drumSequencer, tonysTunes, ...results]
      : [drumPad, pianoTest, synthBox, drumSequencer, tonysTunes];
  }, [results, isClient]);

  const sentinel = useInView(() => {
    // Convex paginated loader pattern
    if (status === "CanLoadMore") loadMore(pageSize);
  });

  // host → iframe messaging (example: pause other games when one starts)
  useEffect(() => {
    const handler = (ev: MessageEvent) => {
      if (!ev?.data || typeof ev.data !== "object") return;
      const { type } = ev.data as { type?: string };
      if (type === "game:start") {
        // broadcast to all frames to pause except sender
        document.querySelectorAll("iframe").forEach((frame) => {
          try {
            frame.contentWindow?.postMessage({ type: "host:pause" }, "*");
          } catch {
            // ignore
          }
        });
      }
      if (type === "game:score") {
        // Optionally forward to an API route or Convex mutation
        // fetch("/api/score", { method: "POST", body: JSON.stringify(ev.data) });
      }
    };
    window.addEventListener("message", handler);
    return () => window.removeEventListener("message", handler);
  }, []);

  return (
    <AuthGate>
      <main className="mx-auto max-w-md md:max-w-lg lg:max-w-xl px-3 py-6 space-y-6">
        <header className="sticky top-0 bg-white/70 dark:bg-zinc-950/70 backdrop-blur z-10 py-3">
          <h1 className="text-2xl md:text-3xl font-bold">Suno Playground</h1>
          <p className="text-sm md:text-base text-zinc-500">
            Scroll to auto‑load more. Tap a card to open the dedicated page.
          </p>
        </header>

        <section className="grid gap-6">
          {gamesWithTest.map((g) => (
            <GameCard key={g._id} game={g} />
          ))}
        </section>

        <div ref={sentinel} />

        {status === "LoadingMore" && (
          <p className="text-center text-sm text-zinc-500">Loading…</p>
        )}

        {status === "Exhausted" && results && results.length === 0 && (
          <p className="text-center text-sm text-zinc-500">
            No games yet. Try seeding some games!
          </p>
        )}
      </main>
    </AuthGate>
  );
}
