'use client';

import React, { useState, useCallback, useEffect } from 'react';
import type {
  RefComponentMountAdapter,
  RefComponentMountParams,
  RefComponentMountResult,
} from '../types/refComponentMount';
import type { ModalRef } from '../types/modal';

type MountQueueItem = {
  id: number,
  RefComponent: RefComponentMountParams<any, any>['RefComponent'],
  props: RefComponentMountParams<any, any>['props'],
  options: RefComponentMountParams<any, any>['options'],
  resolve: (value: RefComponentMountResult<any>) => void,
  reject: (reason?: any) => void,
};

type InTreeMountStore = {
  push: ((item: MountQueueItem) => void) | null,
  remove: ((id: number) => void) | null,
  settledIds: Set<number>,
};

export type InTreeMountAdapter = {
  /** 供 mergeNativeAdapter / mergeRefComponentMount / options.mountAdapter 使用的适配器 */
  adapter: RefComponentMountAdapter,
  /**
   * 挂载 Host，须渲染在组件树内。
   * 与 adapter 通过工厂闭包关联，而非 React Context（命令式 API 无法读取 Context）。
   */
  Host: React.FC,
};

/**
 * 创建「组件树内挂载」适配器与 Host 组件对。
 * 命令式 API 无法 useContext，须在应用层用 useEffect 调用 mergeNativeAdapter({ refComponentMount: adapter }) 或 mergeRefComponentMount(adapter) 注册，
 * 并将 Host 渲染到树中；二者由本工厂闭包绑定，不依赖 Provider/Context 透传。
 * @returns adapter + Host
 */
function createInTreeMountAdapter(): InTreeMountAdapter {
  let mountQueueSeed = 0;
  const store: InTreeMountStore = {
    push: null,
    remove: null,
    settledIds: new Set<number>(),
  };

  /**
   * 将挂载请求推入 Host 队列。
   * @param params - 挂载参数
   * @returns ref 与 destroy
   */
  const mount = <
    M extends ModalRef<any, any, any, any, any, any>,
    P extends Record<string, any> = Record<string, any>,
  >(
    params: RefComponentMountParams<M, P>,
  ): Promise<RefComponentMountResult<M>> => new Promise((resolve, reject) => {
    if (!store.push) {
      reject(new Error(
        '[use-modal-ref] In-tree mount Host is not mounted. '
        + 'Render the Host from createInTreeMountAdapter() in your component tree '
        + 'and call mergeNativeAdapter({ refComponentMount: adapter }) before createRefComponent / showRefModal.',
      ));
      return;
    }
    const id = ++mountQueueSeed;
    store.push({
      id,
      RefComponent: params.RefComponent,
      props: params.props,
      options: params.options,
      resolve: resolve as (value: RefComponentMountResult<any>) => void,
      reject,
    });
  });

  const adapter: RefComponentMountAdapter = {
    id: 'in-tree',
    mount,
  };

  /**
   * 在树内渲染队列中的 RefComponent。
   * @returns Host 节点
   */
  function Host() {
    const [items, setItems] = useState<MountQueueItem[]>([]);

    /**
     * 从队列移除挂载项。
     * @param id - 队列项 id
     */
    const removeItem = useCallback((id: number) => {
      store.settledIds.delete(id);
      setItems((prev) => prev.filter((item) => item.id !== id));
    }, []);

    useEffect(() => {
      store.push = (item) => {
        setItems((prev) => [...prev, item]);
      };
      store.remove = removeItem;
      return () => {
        store.push = null;
        store.remove = null;
      };
    }, [removeItem]);

    return (
      <>
        {items.map((item) => {
          const { RefComponent } = item;
          return (
            <RefComponent
              key={item.id}
              {...(item.props as any)}
              ref={(instance: any) => {
                if (!instance || store.settledIds.has(item.id)) {
                  return;
                }
                store.settledIds.add(item.id);
                const destroy = () => {
                  store.remove?.(item.id);
                };
                item.resolve([instance, destroy]);
                item.options.onRef?.(instance, destroy);
              }}
            />
          );
        })}
      </>
    );
  }

  Host.displayName = 'RefComponentInTreeMountHost';

  return { adapter, Host };
}

export default createInTreeMountAdapter;
