import { mergeProps } from 'zag-ripple';
import { trackSplit, track, type Component, type Tracked } from 'ripple';
import * as toast from '@zag-js/toast';
import { useMachine, normalizeProps } from 'zag-ripple';
import { useEnvironmentContext } from '../../providers/environment';
import { useLocaleContext } from '../../providers/locale';
import { useId } from '../../utils/use-id';
import { ark } from '../factory';
import type { HTMLProps, MaybeTracked, PolymorphicProps } from '../../types';
import type { CreateToasterReturn } from './create-toaster';
import { ToastApiContext } from './use-toast-context';

export type ToastOptions = toast.Options<any>;

export interface ToasterBaseProps extends PolymorphicProps<'div'> {
  toaster: CreateToasterReturn;
  children: Component<{ toast: Tracked<toast.Props<any>> }>;
}

export interface ToasterProps extends HTMLProps<'div'>, ToasterBaseProps {}

export component Toaster(props: MaybeTracked<ToasterProps>) {
  const [children, toaster, localProps] = trackSplit(props, ['children', 'toaster']);

  const locale = useLocaleContext();
  const env = useEnvironmentContext();
  const id = useId();

  const machineProps = track(
    () => ({
      store: @toaster,
      id,
      dir: @locale.dir,
      getRootNode: @env.getRootNode,
    }),
  );

  const service = useMachine(toast.group.machine, machineProps);
  const api = track(() => toast.group.connect(service, normalizeProps));

  let mergedProps = track(() => mergeProps(@api.getGroupProps(), @localProps));

  <ark.div {...@mergedProps}>
    for (const toastItem of @api.getToasts(); index i; key toastItem.id) {
      <ToastActor value={toastItem} {service} index={i} {children} />
    }
  </ark.div>
}

interface ToastActorProps {
  value: toast.Props<any>;
  service: toast.GroupService;
  index: number;
  children: Component<{ toast: Tracked<toast.Props<any>> }>;
}

component ToastActor(props: MaybeTracked<ToastActorProps>) {
  const [children, value, service, index] = trackSplit(props, [
    'children',
    'value',
    'service',
    'index',
  ]);

  const env = useEnvironmentContext();

  const machineProps = track(
    () => ({
      ...@value,
      parent: @service,
      index: @index,
      getRootNode: @env.getRootNode,
    }),
  );

  const actorService = useMachine(toast.machine, machineProps);
  const api = track(() => toast.connect(actorService, normalizeProps));

  ToastApiContext.set(api);

  <@children toast={value} />
}
