import { useEffect, useRef, useState } from "react";

declare global {
  interface Window {
    __zendegi__?: {
      getState: () => string;
      onEvent: (json: string) => void;
      updateState?: (json: string) => void;
    };
    _flutter?: {
      buildConfig?: unknown;
      loader: {
        load: (config?: {
          config?: {
            entrypointBaseUrl?: string;
            assetBase?: string;
          };
          onEntrypointLoaded?: (engineInitializer: {
            initializeEngine: (config: {
              hostElement: HTMLElement;
              assetBase?: string;
            }) => Promise<{ runApp: () => void }>;
          }) => Promise<void>;
        }) => Promise<void>;
      };
    };
  }
}

type FlutterViewProps = {
  state: Record<string, unknown>;
  onEvent: (event: { type: string; payload?: Record<string, unknown> }) => void;
  className?: string;
  height?: number;
};

export function FlutterView({
  state,
  onEvent,
  className,
  height,
}: FlutterViewProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const [status, setStatus] = useState<"loading" | "ready" | "error">(
    "loading"
  );
  const stateRef = useRef(state);
  stateRef.current = state;

  const onEventRef = useRef(onEvent);
  onEventRef.current = onEvent;

  useEffect(() => {
    const container = containerRef.current;
    if (!container) return;

    let pollingInterval: ReturnType<typeof setInterval> | undefined;
    let pollingTimeout: ReturnType<typeof setTimeout> | undefined;

    window.__zendegi__ = {
      getState: () => JSON.stringify(stateRef.current),
      onEvent: (json: string) => {
        const event = JSON.parse(json) as {
          type: string;
          payload?: Record<string, unknown>;
        };
        onEventRef.current(event);
      },
    };

    const init = async () => {
      // Load flutter.js if not already loaded
      if (!window._flutter) {
        await new Promise<void>((resolve, reject) => {
          if (document.querySelector('script[src="/flutter/flutter.js"]')) {
            // Script tag exists but hasn't finished — wait for _flutter to appear
            pollingTimeout = setTimeout(() => {
              clearInterval(pollingInterval);
              reject(
                new Error("Timed out waiting for flutter.js to initialize")
              );
            }, 10_000);
            pollingInterval = setInterval(() => {
              if (window._flutter) {
                clearInterval(pollingInterval);
                clearTimeout(pollingTimeout);
                resolve();
              }
            }, 50);
            return;
          }
          const script = document.createElement("script");
          script.src = "/flutter/flutter.js";
          script.defer = true;
          script.onload = () => resolve();
          script.onerror = () => reject(new Error("Failed to load flutter.js"));
          document.head.appendChild(script);
        });
      }

      // Fetch and set buildConfig so load() works (supports wasm)
      if (!window._flutter!.buildConfig) {
        const res = await fetch("/flutter/build_config.json");
        if (!res.ok) {
          throw new Error(`Failed to fetch build config: ${res.status}`);
        }
        window._flutter!.buildConfig = await res.json();
      }

      try {
        await window._flutter!.loader.load({
          config: {
            entrypointBaseUrl: "/flutter/",
            assetBase: "/flutter/",
          },
          onEntrypointLoaded: async (engineInitializer) => {
            const appRunner = await engineInitializer.initializeEngine({
              hostElement: container,
              assetBase: "/flutter/",
            });
            appRunner.runApp();
            setStatus("ready");
          },
        });
      } catch (error) {
        throw new Error(
          `Flutter engine initialization failed: ${error instanceof Error ? error.message : error}`
        );
      }
    };

    init().catch(() => setStatus("error"));

    return () => {
      clearInterval(pollingInterval);
      clearTimeout(pollingTimeout);
      container.replaceChildren();
      delete (window as Partial<Window>).__zendegi__;
    };
  }, []);

  useEffect(() => {
    window.__zendegi__?.updateState?.(JSON.stringify(state));
  }, [state]);

  return (
    <div className={className} style={{ position: "relative" }}>
      {status === "loading" && (
        <div
          style={{
            position: "absolute",
            inset: 0,
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
          }}
        >
          Loading Flutter...
        </div>
      )}
      {status === "error" && (
        <div
          style={{
            position: "absolute",
            inset: 0,
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            color: "red",
          }}
        >
          Failed to load Flutter view
        </div>
      )}
      <div
        ref={containerRef}
        style={{ width: "100%", height: height ?? 400 }}
      />
    </div>
  );
}
