import React, { useEffect } from 'react';
import { v4 as uuid } from 'uuid';
import { setMeetingSettings } from '/imports/ui/core/local-states/useMeetingSettings';
import MeetingClientSettings from '/imports/ui/Types/meetingClientSettings';
import { ErrorScreen } from '/imports/ui/components/error-screen/component';
import LoadingScreen from '/imports/ui/components/common/loading-screen/component';
import Session from '/imports/ui/services/storage/in-memory';

const connectionTimeout = 60000;

interface Response {
  meeting_clientSettings: Array<{
    clientSettingsJson: MeetingClientSettings,
  }>;
}

declare global {
  interface Window {
    meetingClientSettings: MeetingClientSettings;
  }
}

interface SettingsLoaderProps {
  children: React.ReactNode;
}

const SettingsLoader: React.FC<SettingsLoaderProps> = (props) => {
  const { children } = props;
  const [settingsFetched, setSettingsFetched] = React.useState(false);
  const [error, setError] = React.useState<string | null>(null);
  const [loading, setLoading] = React.useState<boolean>(false);
  const timeoutRef = React.useRef<ReturnType<typeof setTimeout>>();

  useEffect(() => {
    setLoading(true);

    const controller = new AbortController();
    timeoutRef.current = setTimeout(() => {
      controller.abort();
      setError('Timeout fetching client settings');
      setLoading(false);
    }, connectionTimeout);

    const clientSessionUUID = uuid();
    sessionStorage.setItem('clientSessionUUID', clientSessionUUID);

    const urlParams = new URLSearchParams(window.location.search);
    const sessionToken = urlParams.get('sessionToken');

    if (!sessionToken) {
      setLoading(false);
      setError('Missing session token');
      return;
    }

    const pathMatch = window.location.pathname.match('^(.*)/html5client/join$');
    const serverPathPrefix = pathMatch ? pathMatch[1] : '';

    fetch(`https://${window.location.hostname}${serverPathPrefix}/bigbluebutton/api`, {
      headers: {
        'Content-Type': 'application/json',
      },
      signal: controller.signal,
    }).then((resp) => resp.json())
      .then((data) => {
        const url = new URL(`${data.response.graphqlApiUrl}/clientSettings`);
        fetch(url, {
          method: 'get',
          credentials: 'include',
          headers: {
            'x-session-token': sessionToken ?? '',
          },
          signal: controller.signal,
        })
          .then((resp) => resp.json())
          .then((data: Response) => {
            clearTimeout(timeoutRef.current);
            const settings = data?.meeting_clientSettings[0].clientSettingsJson;
            window.meetingClientSettings = JSON.parse(JSON.stringify(settings));
            setMeetingSettings(settings);
            setLoading(false);
            setSettingsFetched(true);
          }).catch(() => {
            setLoading(false);
            setError('Error fetching client settings');
            Session.setItem('errorMessageDescription', 'meeting_ended');
          });
      }).catch((error) => {
        setLoading(false);
        setError('Error fetching GraphQL URL: '.concat(error.message || ''));
      });
  }, []);

  return (
    <>
      {settingsFetched ? children : null}
      {error ? (
        <ErrorScreen
          endedReason={error}
          code={403}
        />
      ) : null}
      {loading ? (
        <LoadingScreen>
          <div style={{ display: 'none' }}>
            Loading...
          </div>
        </LoadingScreen>
      ) : null}
    </>
  );
};

export default SettingsLoader;
