"use client";

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

declare global {
  interface Window {
    loadPyodide: (config: { indexURL: string }) => Promise<PyodideInterface>;
  }
}

interface PyodideInterface {
  runPythonAsync: (code: string) => Promise<unknown>;
  globals: {
    get: (name: string) => unknown;
  };
}

interface PyodideState {
  pyodide: PyodideInterface | null;
  loading: boolean;
  error: string | null;
}

interface RunResult {
  output: unknown;
  error: string | null;
}

const PYODIDE_CDN = "https://cdn.jsdelivr.net/pyodide/v0.25.0/full/";

export function usePyodide() {
  const [state, setState] = useState<PyodideState>({
    pyodide: null,
    loading: true,
    error: null,
  });
  const loadingRef = useRef(false);

  useEffect(() => {
    if (loadingRef.current || state.pyodide) return;
    loadingRef.current = true;

    const loadPyodideScript = async () => {
      // Check if script is already loaded
      if (window.loadPyodide) {
        try {
          const pyodide = await window.loadPyodide({ indexURL: PYODIDE_CDN });
          setState({ pyodide, loading: false, error: null });
        } catch (err) {
          setState({
            pyodide: null,
            loading: false,
            error: err instanceof Error ? err.message : "Failed to load Pyodide",
          });
        }
        return;
      }

      // Load the script
      const script = document.createElement("script");
      script.src = `${PYODIDE_CDN}pyodide.js`;
      script.async = true;

      script.onload = async () => {
        try {
          const pyodide = await window.loadPyodide({ indexURL: PYODIDE_CDN });
          setState({ pyodide, loading: false, error: null });
        } catch (err) {
          setState({
            pyodide: null,
            loading: false,
            error: err instanceof Error ? err.message : "Failed to load Pyodide",
          });
        }
      };

      script.onerror = () => {
        setState({
          pyodide: null,
          loading: false,
          error: "Failed to load Pyodide script",
        });
      };

      document.head.appendChild(script);
    };

    loadPyodideScript();
  }, [state.pyodide]);

  const runPython = useCallback(
    async (code: string, timeout = 5000): Promise<RunResult> => {
      if (!state.pyodide) {
        return { output: null, error: "Pyodide not loaded" };
      }

      return new Promise((resolve) => {
        const timeoutId = setTimeout(() => {
          resolve({ output: null, error: "Execution timed out" });
        }, timeout);

        state.pyodide!
          .runPythonAsync(code)
          .then((result) => {
            clearTimeout(timeoutId);
            resolve({ output: result, error: null });
          })
          .catch((err: Error) => {
            clearTimeout(timeoutId);
            resolve({ output: null, error: err.message });
          });
      });
    },
    [state.pyodide]
  );

  return {
    pyodide: state.pyodide,
    loading: state.loading,
    error: state.error,
    runPython,
  };
}
