import React, { useMemo, useState, useCallback, useEffect } from 'react';
import type { PagesData } from '../common/types/component.types';
import { importFromJSON } from '../common/utils/serialization';
import { formatScopedBindingViolations, validatePagesDataScopedBindings } from '../common/state/validateScopedBindings';
import { RendererRuntimeProvider } from './runtime';
import { Preview } from './components/Preview';

// Ensure component definitions are registered once per bundle load.
import '../common/registry/definitions';

export interface RendererRoutesProps {
  json: string;
  workflow?: { executeUrl: string };
  initialRoute?: string;
}

export const RendererRoutes: React.FC<RendererRoutesProps> = ({ json, workflow, initialRoute }) => {
  const parseResult = useMemo<{ pagesData: PagesData | null; error: string | null }>(() => {
    const parsed = importFromJSON(json);
    if (!parsed || !Array.isArray(parsed.pages)) {
      return { pagesData: null, error: 'Invalid renderer JSON.' };
    }

    const violations = validatePagesDataScopedBindings(parsed);
    if (violations.length > 0) {
      return {
        pagesData: null,
        error: `Invalid scoped bindings detected:\n${formatScopedBindingViolations(violations)}`,
      };
    }

    return { pagesData: parsed, error: null };
  }, [json]);

  const defaultRoute = useMemo(() => {
    if (!parseResult.pagesData) return initialRoute || '/';
    const defaultPage = parseResult.pagesData.pages.find((p) => p.isDefault) || parseResult.pagesData.pages[0];
    return initialRoute || defaultPage?.route || '/';
  }, [parseResult.pagesData, initialRoute]);

  const getHashRoute = (): string | null => {
    const hash = window.location.hash;
    return hash ? hash.slice(1) : null;
  };

  const [currentRoute, setCurrentRoute] = useState<string>(
    getHashRoute() || defaultRoute
  );

  // Set initial hash on mount
  useEffect(() => {
    if (!window.location.hash) {
      window.location.hash = defaultRoute;
    }
  }, []);

  const handleNavigate = useCallback((route: string) => {
    window.location.hash = route;
    setCurrentRoute(route);
  }, []);

  // Sync state with browser back/forward
  useEffect(() => {
    const onHashChange = () => {
      const route = getHashRoute();
      if (route) setCurrentRoute(route);
    };
    window.addEventListener('hashchange', onHashChange);
    return () => window.removeEventListener('hashchange', onHashChange);
  }, []);

  if (!parseResult.pagesData || !Array.isArray(parseResult.pagesData.pages)) {
    return (
      <div style={{ padding: 16, fontFamily: 'system-ui, sans-serif', color: '#333', whiteSpace: 'pre-wrap' }}>
        {parseResult.error || 'Invalid renderer JSON.'}
      </div>
    );
  }

  return (
    <RendererRuntimeProvider
      pagesData={parseResult.pagesData}
      workflow={workflow}
      currentRoute={currentRoute}
      onNavigate={handleNavigate}
    >
      <Preview
        pages={parseResult.pagesData.pages}
        currentRoute={currentRoute}
        onNavigate={handleNavigate}
      />
    </RendererRuntimeProvider>
  );
};
