import { useState, useEffect, useCallback, useMemo } from 'react';
import * as Y from 'yjs';
import { HocuspocusProvider } from '@hocuspocus/provider';
import { useAuthStore } from '@/stores/auth.store';

// Deterministic color from user ID (must match server palette)
const COLLAB_COLORS = [
  '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
  '#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9',
  '#F0B27A', '#82E0AA', '#F1948A', '#AED6F1', '#D7BDE2',
];

function getUserColor(userId: string): string {
  let hash = 0;
  for (let i = 0; i < userId.length; i++) {
    hash = ((hash << 5) - hash + userId.charCodeAt(i)) | 0;
  }
  return COLLAB_COLORS[Math.abs(hash) % COLLAB_COLORS.length] ?? '#85C1E9';
}

export interface Collaborator {
  id: string;
  name: string;
  color: string;
  clientId: number;
}

export interface UseDocsCollaborationReturn {
  yDoc: Y.Doc | null;
  yText: Y.Text | null;
  provider: HocuspocusProvider | null;
  connected: boolean;
  synced: boolean;
  collaborators: Collaborator[];
  /** Whether collaboration is active and synced (ready for binding) */
  active: boolean;
}

/**
 * Manages Y.Doc lifecycle, WebSocket connection, and awareness for collaborative editing.
 * Creates a new Y.Doc + HocuspocusProvider when filePath changes.
 * `active` is only true after the initial Y.js sync completes (content is available).
 */
export function useDocsCollaboration(
  filePath: string | null,
  enabled: boolean,
): UseDocsCollaborationReturn {
  const [connected, setConnected] = useState(false);
  const [synced, setSynced] = useState(false);
  const [collaborators, setCollaborators] = useState<Collaborator[]>([]);

  // Use state (not refs) so changes trigger re-renders for dependent effects
  const [collabState, setCollabState] = useState<{
    yDoc: Y.Doc;
    yText: Y.Text;
    provider: HocuspocusProvider;
  } | null>(null);

  const user = useAuthStore((s) => s.user);
  const accessToken = useAuthStore((s) => s.accessToken);

  // Build WebSocket URL
  const wsUrl = useMemo(() => {
    if (!filePath || !enabled || !accessToken) return null;
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    return `${protocol}//${window.location.host}/api/docs/collaborate`;
  }, [filePath, enabled, accessToken]);

  // Cleanup function
  const cleanup = useCallback(() => {
    setCollabState((prev) => {
      if (prev) {
        prev.provider.disconnect();
        prev.provider.destroy();
        prev.yDoc.destroy();
      }
      return null;
    });
    setConnected(false);
    setSynced(false);
    setCollaborators([]);
  }, []);

  useEffect(() => {
    if (!wsUrl || !filePath || !enabled || !accessToken || !user) {
      cleanup();
      return;
    }

    // Create new Y.Doc and provider
    const doc = new Y.Doc();
    const yText = doc.getText('content');

    const provider = new HocuspocusProvider({
      url: wsUrl,
      name: filePath,
      document: doc,
      token: accessToken,
      onConnect: () => setConnected(true),
      onDisconnect: () => {
        setConnected(false);
        setSynced(false);
      },
      onSynced: () => setSynced(true),
    });

    // Set local awareness state
    provider.setAwarenessField('user', {
      id: user.id,
      name: user.name || user.email.split('@')[0],
      color: getUserColor(user.id),
    });

    // Track collaborators via awareness changes
    const handleAwarenessChange = () => {
      const states = provider.awareness?.getStates();
      if (!states) return;
      const collab: Collaborator[] = [];
      states.forEach((state, clientId) => {
        const u = state.user as { id: string; name: string; color: string } | undefined;
        if (u && u.id !== user.id) {
          collab.push({ id: u.id, name: u.name, color: u.color, clientId });
        }
      });
      setCollaborators(collab);
    };
    provider.awareness?.on('change', handleAwarenessChange);

    // Set state LAST so the component re-renders with everything ready
    setCollabState({ yDoc: doc, yText, provider });

    return () => {
      provider.awareness?.off('change', handleAwarenessChange);
      provider.disconnect();
      provider.destroy();
      doc.destroy();
      setCollabState(null);
      setConnected(false);
      setSynced(false);
      setCollaborators([]);
    };
    // We intentionally only recreate when these core values change
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [wsUrl, filePath, enabled, accessToken, user?.id]);

  return {
    yDoc: collabState?.yDoc ?? null,
    yText: collabState?.yText ?? null,
    provider: collabState?.provider ?? null,
    connected,
    synced,
    collaborators,
    // Only active after provider is connected AND initial sync is complete
    active: enabled && !!collabState && synced && !!filePath,
  };
}
