'use client';

import { useQuery } from '@tanstack/react-query';
import * as Ably from 'ably';
import { AblyProvider, ChannelProvider } from 'ably/react';
import { useCallback, useMemo } from 'react';

import { ProjectMetadataSchema, ProjectStore } from '@/state/projectStore';

import { WorkspaceChangeListener } from './WorkspaceChangeListener';
import { WorkspaceCollaborationInitializer } from './WorkspaceCollaborationInitializer';

type Props = {
  projectId: string;
  project: ProjectStore;
  children?: React.ReactNode;
  onWorkspaceChange?: () => void;
  onKick?: () => void;
};

const ProjectCollaborateClient = ({
  projectId,
  project,
  children,
  onWorkspaceChange,
  onKick,
}: Props) => {
  const getAblyClientId = useCallback(
    async (projectId: string, apiClient: any) => {
      const { data, error } = await apiClient.GET(
        '/api/project/{project_id}/ably-client-id',
        {
          params: { path: { project_id: projectId } },
        }
      );
      if (error) {
        throw new Error('Failed to fetch ably client id');
      }
      return data?.client_id || null;
    },
    []
  );

  // Query for Ably client ID
  const { data: ablyClientId } = useQuery({
    queryKey: ['ablyClientId', projectId],
    queryFn: () => {
      if (!projectId) {
        throw new Error('Project ID is required');
      }
      return getAblyClientId(projectId, project.apiClient);
    },
    enabled:
      !!projectId &&
      !!(project.projectsById[projectId] as ProjectMetadataSchema)?.shared,
  });

  const ablyClient = useMemo(() => {
    if (
      !projectId ||
      !(project.projectsById[projectId] as ProjectMetadataSchema)?.shared ||
      !ablyClientId
    ) {
      return null;
    }
    return new Ably.Realtime({
      authCallback: async (tokenParams, callback) => {
        const { data, error } = await project.apiClient.GET(
          '/api/project/{project_id}/ably-token',
          {
            params: {
              path: { project_id: projectId },
            },
          }
        );
        if (error) {
          callback(error, null);
        } else {
          if (data.token) {
            callback(null, JSON.parse(data.token));
          } else {
            callback('No token returned', null);
          }
        }
      },
      clientId: ablyClientId,
      useTokenAuth: true,
    });
  }, [
    projectId,
    (project.projectsById[projectId] as ProjectMetadataSchema)?.shared,
    ablyClientId,
    project,
  ]);

  // Don't render anything if we don't have an ably client
  if (!ablyClient) {
    return null;
  }

  return (
    <AblyProvider client={ablyClient}>
      <ChannelProvider channelName={`suno-collab-workspace:${projectId}`}>
        <WorkspaceChangeListener
          project={project}
          onWorkspaceChange={onWorkspaceChange}
          onKick={onKick}
        />
        <WorkspaceCollaborationInitializer project={project} />
        {children}
      </ChannelProvider>
    </AblyProvider>
  );
};

export default ProjectCollaborateClient;
