interface BrowserSupportAdapter {
  activation:
    | 'bundled-module'
    | 'dependency-module'
    | 'prebuilt-script'
    | 'source-sidecar'
    | 'native-sidecar'
    | 'editor-sidecar'
    | 'qa-sidecar'
    | 'reference-only';
  description: string;
  id: string;
  packageName?: string;
  phase: '1E' | '1F' | '1G' | '1H' | '1I' | '1J';
  queuePosition?: number;
  repo: string;
  sourcePathHint: string;
}

interface LoadedAdapter {
  details?: string[];
  id: string;
  module?: unknown;
  note?: string;
  status: 'loaded' | 'deferred';
}

const ScriptLoadCache = new Map<string, Promise<unknown>>();

function isDistShell(): boolean
{
  return new URL(document.baseURI).pathname.includes('/Content/Browser/dist/');
}

function resolveRepoAssetUrl(RepoRelativePath: string): string
{
  const Prefix = isDistShell() ? '../../../' : '../../';
  return new URL(`${Prefix}${RepoRelativePath}`, document.baseURI).toString();
}

function loadExternalScript(RepoRelativePath: string): Promise<unknown>
{
  const ResolvedUrl = resolveRepoAssetUrl(RepoRelativePath);
  if (ScriptLoadCache.has(ResolvedUrl))
  {
    return ScriptLoadCache.get(ResolvedUrl) as Promise<unknown>;
  }

  const LoadPromise = new Promise<unknown>((Resolve, Reject) =>
  {
    const ExistingElement = document.querySelector<HTMLScriptElement>(
      `script[data-hypertwist-src="${ResolvedUrl}"]`
    );
    if (ExistingElement)
    {
      ExistingElement.addEventListener('load', () => Resolve(undefined), { once: true });
      ExistingElement.addEventListener('error', () => Reject(new Error(`Failed to load ${ResolvedUrl}`)), { once: true });
      return;
    }

    const ScriptElement = document.createElement('script');
    ScriptElement.src = ResolvedUrl;
    ScriptElement.async = true;
    ScriptElement.dataset.hypertwistSrc = ResolvedUrl;
    ScriptElement.onload = () => Resolve(undefined);
    ScriptElement.onerror = () => Reject(new Error(`Failed to load ${ResolvedUrl}`));
    document.head.appendChild(ScriptElement);
  });

  ScriptLoadCache.set(ResolvedUrl, LoadPromise);
  return LoadPromise;
}

async function loadSpatialStack(): Promise<LoadedAdapter>
{
  const [
    Fiber,
    Drei,
    ReactPostprocessing,
    Postprocessing,
    Leva,
    Maath,
    ThreeStdLib,
    Zustand,
    UseGesture,
    ReactSpringThree,
    ReactSpringWeb,
    UIKit
  ] = await Promise.all([
    import('@react-three/fiber'),
    import('@react-three/drei'),
    import('@react-three/postprocessing'),
    import('postprocessing'),
    import('leva'),
    import('maath'),
    import('three-stdlib'),
    import('zustand'),
    import('@use-gesture/react'),
    import('@react-spring/three'),
    import('@react-spring/web'),
    import('@pmndrs/uikit')
  ]);

  return {
    id: 'phase-1h-spatial-stack',
    status: 'loaded',
    module: {
      Fiber,
      Drei,
      ReactPostprocessing,
      Postprocessing,
      Leva,
      Maath,
      ThreeStdLib,
      Zustand,
      UseGesture,
      ReactSpringThree,
      ReactSpringWeb,
      UIKit
    },
    details: [
      '@react-three/fiber',
      '@react-three/drei',
      '@react-three/postprocessing',
      'postprocessing',
      'leva',
      'maath',
      'three-stdlib',
      'zustand',
      '@use-gesture/react',
      '@react-spring/three',
      '@react-spring/web',
      '@pmndrs/uikit'
    ]
  };
}

async function loadAnalyticsStack(): Promise<LoadedAdapter>
{
  const [ECharts, ZRender] = await Promise.all([
    import('echarts'),
    import('zrender')
  ]);
  await import('echarts-gl');

  return {
    id: 'phase-1i-analytics-stack',
    status: 'loaded',
    module: {
      ECharts,
      ZRender
    },
    details: [
      'echarts',
      'zrender',
      'echarts-gl'
    ]
  };
}

async function loadViewerStack(): Promise<LoadedAdapter>
{
  await Promise.all([
    import('@google/model-viewer'),
    import('@google/model-viewer-effects')
  ]);
  const GltfViewer = await import('@khronosgroup/gltf-viewer');

  return {
    id: 'phase-1j-viewer-stack',
    status: 'loaded',
    module: {
      ModelViewerElement: customElements.get('model-viewer'),
      GltfViewer
    },
    details: [
      '@google/model-viewer',
      '@google/model-viewer-effects',
      '@khronosgroup/gltf-viewer'
    ]
  };
}

async function loadClayViewerStack(): Promise<LoadedAdapter>
{
  await loadExternalScript('.external/claygl/dist/claygl.js');
  await loadExternalScript('.external/clay-viewer/dist/clay-viewer.js');

  const GlobalWindow = window as Window & {
    ClayViewer?: unknown;
    clay?: unknown;
  };

  return {
    id: 'phase-1h-clay-viewer-stack',
    status: 'loaded',
    module: {
      clay: GlobalWindow.clay,
      ClayViewer: GlobalWindow.ClayViewer
    },
    details: [
      '.external/claygl/dist/claygl.js',
      '.external/clay-viewer/dist/clay-viewer.js'
    ]
  };
}

export const BrowserSupportAdapters: BrowserSupportAdapter[] = [
  {
    id: '1f-cahidenes-native-solver',
    phase: '1F',
    queuePosition: 1,
    repo: 'cahidenes/rubiks-cube-solver',
    activation: 'native-sidecar',
    sourcePathHint: '.external/rubiks-cube-solver',
    description: 'Python solver and visualizer retained behind the first-party comparison-process boundary.'
  },
  {
    id: '1e-gltf-sample-renderer',
    phase: '1E',
    queuePosition: 23,
    repo: 'KhronosGroup/glTF-Sample-Renderer',
    activation: 'bundled-module',
    packageName: '@khronosgroup/gltf-viewer',
    sourcePathHint: '.external/glTF-Sample-Renderer',
    description: 'Reference glTF renderer and viewer module wired into the first-party browser runtime.'
  },
  {
    id: '1g-tentone-native-solver',
    phase: '1G',
    queuePosition: 2,
    repo: 'tentone/rubix-solver',
    activation: 'native-sidecar',
    sourcePathHint: '.external/rubix-solver',
    description: 'Native/OpenCV solver adjunct retained as a browser-shell fallback lane rather than a direct npm package.'
  },
  {
    id: '1h-code-vr',
    phase: '1H',
    queuePosition: 3,
    repo: 'NuiLab/code-vr',
    activation: 'source-sidecar',
    sourcePathHint: '.external/code-vr',
    description: 'Rust donor retained as a source-sidecar surface for follow-up browser spatial composition.'
  },
  {
    id: '1h-claygl',
    phase: '1H',
    queuePosition: 4,
    repo: 'pissang/claygl',
    activation: 'prebuilt-script',
    sourcePathHint: '.external/claygl/dist/claygl.js',
    description: 'Prebuilt ClayGL runtime script bridged into the browser shell for viewer and QA surfaces.'
  },
  {
    id: '1h-clay-viewer',
    phase: '1H',
    queuePosition: 5,
    repo: 'pissang/clay-viewer',
    activation: 'prebuilt-script',
    sourcePathHint: '.external/clay-viewer/dist/clay-viewer.js',
    description: 'Prebuilt Clay Viewer shell loaded beside ClayGL for bounded browser inspection.'
  },
  {
    id: '1h-postprocessing',
    phase: '1H',
    queuePosition: 6,
    repo: 'pmndrs/postprocessing',
    activation: 'bundled-module',
    packageName: 'postprocessing',
    sourcePathHint: '.external/postprocessing',
    description: 'Three.js post-processing core bundled into the runtime module graph.'
  },
  {
    id: '1h-react-postprocessing',
    phase: '1H',
    queuePosition: 7,
    repo: 'pmndrs/react-postprocessing',
    activation: 'bundled-module',
    packageName: '@react-three/postprocessing',
    sourcePathHint: '.external/react-postprocessing',
    description: 'React bridge for post-processing loaded into the browser spatial stack.'
  },
  {
    id: '1h-drei',
    phase: '1H',
    queuePosition: 8,
    repo: 'pmndrs/drei',
    activation: 'bundled-module',
    packageName: '@react-three/drei',
    sourcePathHint: '.external/drei',
    description: 'Drei helper surface bundled for browser-spatial utility composition.'
  },
  {
    id: '1h-uikit',
    phase: '1H',
    queuePosition: 9,
    repo: 'pmndrs/uikit',
    activation: 'bundled-module',
    packageName: '@pmndrs/uikit',
    sourcePathHint: '.external/uikit',
    description: 'World-anchored UI kit bundled for browser-spatial HUD and control surfaces.'
  },
  {
    id: '1h-three-stdlib',
    phase: '1H',
    queuePosition: 10,
    repo: 'pmndrs/three-stdlib',
    activation: 'bundled-module',
    packageName: 'three-stdlib',
    sourcePathHint: '.external/three-stdlib',
    description: 'Three.js helper library bundled for browser runtime support.'
  },
  {
    id: '1h-maath',
    phase: '1H',
    queuePosition: 11,
    repo: 'pmndrs/maath',
    activation: 'bundled-module',
    packageName: 'maath',
    sourcePathHint: '.external/maath',
    description: 'Animation and math helper pack bundled into the runtime.'
  },
  {
    id: '1h-zustand',
    phase: '1H',
    queuePosition: 12,
    repo: 'pmndrs/zustand',
    activation: 'bundled-module',
    packageName: 'zustand',
    sourcePathHint: '.external/zustand',
    description: 'State-store runtime bundled for browser shell state and derived panel demos.'
  },
  {
    id: '1h-leva',
    phase: '1H',
    queuePosition: 13,
    repo: 'pmndrs/leva',
    activation: 'bundled-module',
    packageName: 'leva',
    sourcePathHint: '.external/leva',
    description: 'Parameter-control runtime bundled for future tuning overlays.'
  },
  {
    id: '1h-use-gesture',
    phase: '1H',
    queuePosition: 14,
    repo: 'pmndrs/use-gesture',
    activation: 'bundled-module',
    packageName: '@use-gesture/react',
    sourcePathHint: '.external/use-gesture',
    description: 'Gesture capture hooks bundled for browser interaction surfaces.'
  },
  {
    id: '1h-react-spring',
    phase: '1H',
    queuePosition: 15,
    repo: 'pmndrs/react-spring',
    activation: 'bundled-module',
    packageName: '@react-spring/three and @react-spring/web',
    sourcePathHint: '.external/react-spring',
    description: 'Motion and interpolation runtime bundled for browser spatial transitions.'
  },
  {
    id: '1h-react-spring-core',
    phase: '1H',
    queuePosition: 24,
    repo: '@react-spring/core',
    activation: 'dependency-module',
    packageName: '@react-spring/core',
    sourcePathHint: '.external/react-spring/packages/core',
    description: 'Core spring controller is bundled transitively through the owned React Spring runtime entrypoints.'
  },
  {
    id: '1h-react-spring-shared',
    phase: '1H',
    queuePosition: 25,
    repo: '@react-spring/shared',
    activation: 'dependency-module',
    packageName: '@react-spring/shared',
    sourcePathHint: '.external/react-spring/packages/shared',
    description: 'Shared React Spring utilities are retained and locked as transitive runtime dependencies.'
  },
  {
    id: '1h-react-spring-types',
    phase: '1H',
    queuePosition: 26,
    repo: '@react-spring/types',
    activation: 'reference-only',
    packageName: '@react-spring/types',
    sourcePathHint: '.external/react-spring/packages/types',
    description: 'Compile-time type declarations remain dependency evidence and are not presented as a player runtime.'
  },
  {
    id: '1h-react-spring-parallax',
    phase: '1H',
    queuePosition: 27,
    repo: '@react-spring/parallax',
    activation: 'dependency-module',
    packageName: '@react-spring/web (Parallax export)',
    sourcePathHint: '.external/react-spring/packages/parallax',
    description: 'Parallax behavior is supplied through the bundled React Spring web entrypoint rather than a fabricated standalone package.'
  },
  {
    id: '1h-react-spring-rafz',
    phase: '1H',
    queuePosition: 28,
    repo: '@react-spring/rafz',
    activation: 'dependency-module',
    packageName: '@react-spring/rafz',
    sourcePathHint: '.external/react-spring/packages/rafz',
    description: 'The request-animation-frame scheduler is locked as a transitive React Spring runtime dependency.'
  },
  {
    id: '1h-react-spring-animated',
    phase: '1H',
    queuePosition: 29,
    repo: '@react-spring/animated',
    activation: 'dependency-module',
    packageName: '@react-spring/animated',
    sourcePathHint: '.external/react-spring/packages/animated',
    description: 'Animated-value primitives are locked as a transitive React Spring runtime dependency.'
  },
  {
    id: '1i-zrender',
    phase: '1I',
    queuePosition: 20,
    repo: 'ecomfe/zrender',
    activation: 'bundled-module',
    packageName: 'zrender',
    sourcePathHint: '.external/zrender',
    description: '2D render engine bundled beneath the analytics surface.'
  },
  {
    id: '1i-echarts-gl',
    phase: '1I',
    queuePosition: 21,
    repo: 'ecomfe/echarts-gl',
    activation: 'bundled-module',
    packageName: 'echarts-gl',
    sourcePathHint: '.external/echarts-gl',
    description: '3D analytics extension bundled beneath the ECharts runtime.'
  },
  {
    id: '1j-model-viewer',
    phase: '1J',
    repo: 'google/model-viewer/packages/model-viewer',
    activation: 'bundled-module',
    packageName: '@google/model-viewer',
    sourcePathHint: '.external/model-viewer/packages/model-viewer',
    description: 'Model Viewer web component bundled into the browser shell.'
  },
  {
    id: '1j-model-viewer-effects',
    phase: '1J',
    queuePosition: 16,
    repo: 'google/model-viewer/packages/model-viewer-effects',
    activation: 'bundled-module',
    packageName: '@google/model-viewer-effects',
    sourcePathHint: '.external/model-viewer/packages/model-viewer-effects',
    description: 'Effects package bundled beside model-viewer for decorated previews.'
  },
  {
    id: '1j-model-viewer-docs',
    phase: '1J',
    queuePosition: 17,
    repo: 'google/model-viewer/packages/modelviewer.dev',
    activation: 'reference-only',
    sourcePathHint: '.external/model-viewer/packages/modelviewer.dev',
    description: 'The documentation application is retained as reference evidence and is intentionally absent from the player runtime.'
  },
  {
    id: '1j-space-opera',
    phase: '1J',
    queuePosition: 19,
    repo: 'google/model-viewer/packages/space-opera',
    activation: 'editor-sidecar',
    sourcePathHint: '.external/model-viewer/packages/space-opera',
    description: 'Editor-oriented inspection UI retained as a sidecar instead of a default runtime export.'
  },
  {
    id: '1j-render-fidelity-tools',
    phase: '1J',
    queuePosition: 18,
    repo: 'google/model-viewer/packages/render-fidelity-tools',
    activation: 'qa-sidecar',
    sourcePathHint: '.external/model-viewer/packages/render-fidelity-tools',
    description: 'Renderer comparison and fidelity tooling kept in the QA lane rather than loaded by default.'
  },
  {
    id: '1e-gltf-sample-viewer',
    phase: '1E',
    queuePosition: 22,
    repo: 'KhronosGroup/glTF-Sample-Viewer',
    activation: 'reference-only',
    sourcePathHint: '.external/glTF-Sample-Viewer',
    description: 'The reference viewer remains a standards and QA comparison surface rather than a second embedded player renderer.'
  }
];

export function listAdapters(): BrowserSupportAdapter[]
{
  return [...BrowserSupportAdapters];
}

export async function loadAdapter(AdapterId: string): Promise<LoadedAdapter>
{
  switch (AdapterId)
  {
    case '1e-gltf-sample-renderer':
      return loadViewerStack();

    case '1f-cahidenes-native-solver':
    case '1g-tentone-native-solver':
      return {
        id: AdapterId,
        status: 'deferred',
        note: 'Use the first-party process boundary to route into this native or Python solver adjunct.'
      };

    case '1h-code-vr':
      return {
        id: AdapterId,
        status: 'deferred',
        note: 'code-vr stays source-sidecar until a dedicated Rust or WASM bridge is assigned.'
      };

    case '1h-claygl':
    case '1h-clay-viewer':
      return loadClayViewerStack();

    case '1h-postprocessing':
    case '1h-react-postprocessing':
    case '1h-drei':
    case '1h-uikit':
    case '1h-three-stdlib':
    case '1h-maath':
    case '1h-zustand':
    case '1h-leva':
    case '1h-use-gesture':
    case '1h-react-spring':
    case '1h-react-spring-core':
    case '1h-react-spring-shared':
    case '1h-react-spring-parallax':
    case '1h-react-spring-rafz':
    case '1h-react-spring-animated':
      return loadSpatialStack();

    case '1i-zrender':
    case '1i-echarts-gl':
      return loadAnalyticsStack();

    case '1j-model-viewer':
    case '1j-model-viewer-effects':
      return loadViewerStack();

    case '1j-space-opera':
      return {
        id: AdapterId,
        status: 'deferred',
        note: 'space-opera remains intentionally outside the default runtime and is surfaced as an editor-sidecar.'
      };

    case '1j-render-fidelity-tools':
      return {
        id: AdapterId,
        status: 'deferred',
        note: 'render-fidelity-tools stays in the QA lane and is not auto-loaded in the browser shell.'
      };

    case '1h-react-spring-types':
    case '1j-model-viewer-docs':
    case '1e-gltf-sample-viewer':
      return {
        id: AdapterId,
        status: 'deferred',
        note: 'This row is retained as dependency or reference evidence and is intentionally not loaded as a player runtime.'
      };

    default:
      throw new Error(`Unknown browser support adapter: ${AdapterId}`);
  }
}

export function resolveSupportAssetUrl(RepoRelativePath: string): string
{
  return resolveRepoAssetUrl(RepoRelativePath);
}
