"use client";

import { DeviceStream } from "@mobilerun/react";
import "@mobilerun/react/styles.css";
import { useCallback, useEffect, useRef, useState } from "react";

export interface StreamCredentials {
  streamUrl: string | null;
  streamToken: string | null;
  state: string;
}

export async function fetchStream(
  signal?: AbortSignal,
): Promise<StreamCredentials> {
  const response = await fetch("/api/phone/stream", {
    credentials: "same-origin",
    cache: "no-store",
    signal,
  });
  if (!response.ok) throw new Error(`Stream unavailable (${response.status})`);
  const data: unknown = await response.json();
  if (!data || typeof data !== "object")
    throw new Error("Invalid stream response");
  const { streamUrl, streamToken, state } = data as Partial<StreamCredentials>;
  const ready =
    typeof streamUrl === "string" &&
    streamUrl.length > 0 &&
    typeof streamToken === "string" &&
    streamToken.length > 0;
  const waiting = streamUrl === null && streamToken === null;
  if (typeof state !== "string" || !state || (!ready && !waiting)) {
    throw new Error("Invalid stream response");
  }
  return {
    streamUrl: streamUrl ?? null,
    streamToken: streamToken ?? null,
    state,
  };
}

export function PhonePanel() {
  const [credentials, setCredentials] = useState<StreamCredentials>();
  const [error, setError] = useState<string>();
  const pending = useRef<AbortController | null>(null);

  const reloadCredentials = useCallback(async () => {
    pending.current?.abort();
    const controller = new AbortController();
    pending.current = controller;
    try {
      const next = await fetchStream(controller.signal);
      if (!controller.signal.aborted) {
        setCredentials(next);
        setError(undefined);
      }
    } catch {
      if (!controller.signal.aborted) {
        setCredentials(undefined);
        setError("Unable to load your phone. Try again.");
      }
    }
  }, []);

  useEffect(() => {
    void reloadCredentials();
    return () => pending.current?.abort();
  }, [reloadCredentials]);

  useEffect(() => {
    if (!credentials || credentials.streamUrl || error) return;
    const timer = window.setTimeout(() => void reloadCredentials(), 3000);
    return () => window.clearTimeout(timer);
  }, [credentials, error, reloadCredentials]);

  if (error)
    return (
      <div role="alert">
        {error} <button onClick={() => void reloadCredentials()}>Retry</button>
      </div>
    );
  return (
    <DeviceStream
      streamUrl={credentials?.streamUrl ?? undefined}
      streamToken={credentials?.streamToken ?? undefined}
      placeholderLabel={credentials?.state ?? "loading"}
      hasControl
      muted
      onStreamHealed={reloadCredentials}
    />
  );
}
