import { participantAttributesObserver } from '@cc-livekit/components-core';
import type { Participant } from '@cc-livekit/livekit-client';
import * as React from 'react';
import { useEnsureParticipant, useMaybeParticipantContext } from '../context';
import { useObservableState } from './internal';

/**
 * The `useParticipantAttributes` hook returns the attributes of a given participant and allows to set them.
 * It requires a `Participant` object passed as property or via the `ParticipantContext`.
 *
 * @example
 * ```tsx
 * const { attributes } = useParticipantAttributes({ participant });
 * ```
 * @public
 */
export interface UseParticipantAttributesOptions {
  participant?: Participant;
}

/** @public */
export function useParticipantAttributes(props: UseParticipantAttributesOptions = {}) {
  const participantContext = useMaybeParticipantContext();
  const p = props.participant ?? participantContext;
  const attributeObserver = React.useMemo(
    // weird typescript constraint
    () => (p ? participantAttributesObserver(p) : participantAttributesObserver(p)),
    [p],
  );
  const attributeState = useObservableState(attributeObserver, {
    attributes: p?.attributes,
  });

  return attributeState;
}

/**
 * The `useParticipantAttribute` hook returns the latest value of a given attribute key of a participant.
 * It requires a `Participant` object passed as property in the `UseParticipantAttributesOptions` or via the `ParticipantContext`.
 *
 * @example
 * ```tsx
 * const myAttributeValue = useParticipantAttribute('targetAttributeName');
 * ```
 * @public
 */
export function useParticipantAttribute(
  attributeKey: string,
  options: UseParticipantAttributesOptions = {},
) {
  const p = useEnsureParticipant(options.participant);
  const [attribute, setAttribute] = React.useState(p.attributes[attributeKey]);

  React.useEffect(() => {
    if (!p) {
      return;
    }
    const subscription = participantAttributesObserver(p).subscribe((val) => {
      if (val.changed[attributeKey] !== undefined) {
        setAttribute(val.attributes[attributeKey]);
      }
    });
    return () => {
      subscription.unsubscribe();
    };
  }, [p, attributeKey]);

  return attribute;
}
