import { ChatClient } from '@ably/chat';
import { ChatClientProvider, ChatRoomProvider } from '@ably/chat/react';
import { useQuery } from '@tanstack/react-query';
import * as Ably from 'ably';
import {
  ReactNode,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import { SkeletonBone } from '@/components/layout/Skeleton';
import { useApiClient } from '@/lib/apiClient';

const ROOM_OPTIONS = {
  occupancy: { enableEvents: true },
};

interface LiveRadioAblyProviderProps {
  stationId: string;
  children: ReactNode;
}

// Skeleton component that matches the radio page layout
const RadioPageSkeleton = () => {
  return (
    <div className='relative flex h-[calc(100dvh-100px-env(safe-area-inset-bottom,0px))] w-full touch-none flex-col bg-background-primary p-0 supports-[height:100dvh]:h-[calc(100dvh-100px-env(safe-area-inset-bottom,0px))] supports-[height:100svh]:h-[calc(100svh-100px-env(safe-area-inset-bottom,0px))] md:h-screen md:p-4'>
      {/* Top bar skeleton */}
      <div className='relative top-0 right-0 mb-2 w-full max-md:hidden'>
        <div className='flex items-center justify-between p-4'>
          <SkeletonBone className='h-8 w-32 rounded-md bg-white/10' />
          <div className='flex items-center gap-4'>
            <SkeletonBone className='h-10 w-64 rounded-md bg-white/10' />
            <SkeletonBone className='h-10 w-24 rounded-md bg-white/10' />
          </div>
        </div>
      </div>

      {/* Background container */}
      <div className='relative flex w-full flex-1 flex-col items-center justify-center overflow-hidden rounded-none bg-black/20 md:rounded-[24px]'>
        {/* Background overlay */}
        <div className='fixed inset-0 h-[calc(100dvh-50px-env(safe-area-inset-bottom,0px))] bg-linear-to-b from-black/15 via-black/25 via-60% to-black md:absolute md:h-screen md:bg-[radial-gradient(ellipse_at_center,transparent_0%,rgba(0,0,0,0.2)_50%,rgba(0,0,0,0.6)_100%)]' />

        {/* Main content with floating banners */}
        <div className='absolute right-2 bottom-4 left-2 pb-[calc(env(safe-area-inset-bottom,0px)+4px)] md:right-6 md:bottom-6 md:left-6'>
          <div className='flex max-h-[calc(100vh-env(safe-area-inset-bottom,0px))] flex-col justify-start gap-4 overflow-y-auto md:max-h-none xl:flex-row xl:items-end'>
            {/* Main Radio Banner Skeleton */}
            <div className='w-full rounded-[18px] border border-white/10 bg-black/20 p-4 shadow-lg backdrop-blur-xl md:p-6 xl:w-[650px] xl:shrink-0'>
              <div className='space-y-3'>
                <SkeletonBone className='h-6 w-48 rounded-md bg-white/20' />
                <SkeletonBone className='h-4 w-64 rounded-md bg-white/10' />
              </div>
            </div>

            {/* Chat Skeleton */}
            <div className='w-full rounded-[18px] border border-white/10 bg-black/20 shadow-lg backdrop-blur-xl xl:max-w-[650px] xl:min-w-[300px] xl:flex-1'>
              {/* Chat messages */}
              <div className='max-h-[300px] space-y-3 overflow-hidden p-4'>
                {[...Array(8)].map((_, index) => (
                  <div
                    key={index}
                    className='flex items-center gap-2 px-1.5 py-1 md:gap-3 md:px-2'
                  >
                    <SkeletonBone className='h-5 w-5 shrink-0 rounded-full bg-white/10 md:h-6 md:w-6' />
                    <div className='flex-1 space-y-1'>
                      <div className='flex items-center gap-2'>
                        <SkeletonBone className='h-3 w-16 rounded-md bg-white/10' />
                        <SkeletonBone className='h-3 flex-1 rounded-md bg-white/10' />
                      </div>
                    </div>
                  </div>
                ))}
              </div>

              {/* Chat input */}
              <div className='border-t border-white/10 p-4'>
                <SkeletonBone className='h-10 w-full rounded-md bg-white/10' />
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

const LiveRadioAblyProvider = ({
  stationId,
  children,
}: LiveRadioAblyProviderProps) => {
  const { session } = useStores();
  const apiClient = useApiClient();
  const ablyClientRef = useRef<Ably.Realtime | null>(null);
  const [chatClient, setChatClient] = useState<ChatClient | null>(null);

  const getAblyClientId = useCallback(async () => {
    const { data, error } = await apiClient.GET(
      '/api/living_radio/{station_id}/ably-client-id',
      {
        params: { path: { station_id: stationId } },
      }
    );
    if (error) {
      throw new Error('Failed to fetch ably client id');
    }
    return data?.client_id || null;
  }, [apiClient, stationId]);

  const { data: ablyClientId } = useQuery({
    queryKey: ['ablyClientId'],
    queryFn: getAblyClientId,
    enabled: !!session.user, // Only fetch if user is logged in
    staleTime: Infinity,
  });

  const cleanupConnection = useCallback(() => {
    if (ablyClientRef.current) {
      ablyClientRef.current.close();
      ablyClientRef.current = null;
      setChatClient(null);
    }
  }, []);

  const createAuthCallback = useCallback(
    () => async (_tokenParams: any, callback: any) => {
      try {
        const endpoint = session.user
          ? '/api/living_radio/{station_id}/ably-token'
          : '/api/living_radio/{station_id}/anonymous-ably-token';

        const { data, error } = await apiClient.GET(endpoint, {
          params: { path: { station_id: stationId } },
        });

        if (error) {
          callback(error, null);
        } else {
          callback(null, JSON.parse(data.token));
        }
      } catch (error) {
        callback(error, null);
      }
    },
    [session.user, apiClient, stationId]
  );

  useEffect(() => {
    // Don't connect if session isn't loaded or no client ID
    if (!session.sessionIsLoaded || (session.user && !ablyClientId)) {
      return;
    }

    const clientId = session.user ? ablyClientId || 'unknown' : 'anonymous';
    const authCallback = createAuthCallback();

    const newAblyClient = new Ably.Realtime({
      authCallback,
      clientId,
      useTokenAuth: true,
    });

    const newChatClient = new ChatClient(newAblyClient);
    ablyClientRef.current = newAblyClient;
    setChatClient(newChatClient);

    // Ensure connection is closed when dependencies change or component unmounts
    return cleanupConnection;
  }, [
    ablyClientId,
    session.user,
    stationId,
    session.sessionIsLoaded,
    cleanupConnection,
    createAuthCallback,
  ]);

  const roomOptions = ROOM_OPTIONS;
  const roomName = useMemo(
    () => `suno-living-radio-chat:${stationId}`,
    [stationId]
  );

  if (!chatClient) return <RadioPageSkeleton />;

  return (
    <ChatClientProvider client={chatClient}>
      <ChatRoomProvider name={roomName} options={roomOptions}>
        {children}
      </ChatRoomProvider>
    </ChatClientProvider>
  );
};

export default LiveRadioAblyProvider;
