import {
  useContext,
  useState,
  createContext,
  useCallback,
  useEffect,
  useRef,
} from 'react';
import React from 'react';
import type { FC } from 'react';
import { IStorage } from '../interface/IStorage';
import { BasicStorage } from '../BasicStorage';
import { ChatMessage } from '../types/ChatMessage';
type ChatRequestType = 'http' | 'ws';
type ChatContextProps = {
  messagesList: ChatMessage[];
  chatRequestType: ChatRequestType;
  sendMessage: (params: any) => void;
  setChatRequestType: (chatType: ChatRequestType) => void;
  addMessageList: (
    message: ChatMessage | ChatMessage[],
    addType?: string,
  ) => void;
  upDateMessageItem: (message: ChatMessage) => void;
  getMessageItem: (key: string, callback: (item: ChatMessage) => void) => void;
  setMessageList: (messageList: ChatMessage[]) => void;
  removeMessageList: (keys: string | string[]) => void;
  handleRequest: (
    params: ChatMessage,
    service: (params: any) => Promise<any>,
    callback: (res: any) => void,
  ) => void;
};
type WsServiceRes = {
  send: (params: any) => void;
  close: () => void;
};

type ChatProviderConfig = {
  initChatRequestType: ChatRequestType;
  requests: {
    send: (params: any) => Promise<any>;
    [key: string]: (params: any) => Promise<any>;
  };
  wsRequest?: (
    cxt: Pick<ChatContextProps, 'addMessageList' | 'upDateMessageItem'>,
  ) => WsServiceRes;
};
type ChatProviderProps = {
  config: ChatProviderConfig;
  storage: IStorage;
};
type UseStoragProps = {
  initMessageList?: ChatMessage[];
};
type UseStorage = (param: UseStoragProps) => void;

const ChatContext = createContext<ChatContextProps | undefined>(undefined);

ChatContext.displayName = 'ChatContext';
export const useChat = (): ChatContextProps => {
  const context = useContext(ChatContext);

  if (!context) {
    throw new Error('useChat must be within ChatProvider');
  }

  return context;
};
export const useStorage: UseStorage = ({ initMessageList = [] }) => {
  const Storage = new BasicStorage({
    initMessageList: initMessageList,
  });
  return [Storage];
};

export const ChatProvider: FC<ChatProviderProps> = ({
  children,
  storage,
  config,
}) => {
  const { initChatRequestType, requests, wsRequest } = config;

  const [state, setState] = useState(storage.getMessageList());
  const [chatRequestType, setChatRequestType] = useState<ChatRequestType>(
    initChatRequestType || 'http',
  );
  const wsRequestRef = useRef<WsServiceRes>();

  /**
   * @description
   * @param params 发送的参数
   *
   *
   * **/
  const sendMessage = useCallback(
    async (params: ChatMessage) => {
      if (chatRequestType === 'http') {
        storage.addMessageList(params);
        const data = await requests.send(params);
        let newMessageList = storage.addMessageList(data);
        setState(newMessageList);
      }
      if (chatRequestType === 'ws') {
        let newMessageList = storage.addMessageList(params);
        wsRequestRef.current?.send(params);
        setState(newMessageList);
      }
    },
    [chatRequestType],
  );
  /**
   *
   * @param message 添加的数据；
   * @param addType 添加的类型 默认为push (push | unshift)
   **/
  const addMessageList = (
    message: ChatMessage | ChatMessage[],
    addType: string = 'push',
  ) => {
    const messageList = storage.addMessageList(message, addType);
    setState(messageList);
  };
  /**
   * @param message 更新的数据
   * **/
  const upDateMessageItem = (message: ChatMessage) => {
    const messageList = storage.updateMessageItem(message);
    setState(messageList);
  };

  /**
   *
   *
   */
  const getMessageItem = (
    key: string,
    callback: (item: ChatMessage) => void,
  ) => {
    callback(storage.getMessageItem(key)[0]);
  };
  const setMessageList = (message: ChatMessage[]) => {
    const messageList = storage.setMessageList(message);
    setState(messageList);
  };
  const removeMessageList = (keys: string | string[]) => {
    const messageList = storage.removeMessageList(keys);
    setState(messageList);
  };
  const handleRequest = async (
    params: ChatMessage,
    service: (params: any) => Promise<any>,
    callback: (res: any) => void,
  ) => {
    const data = await service(params);
    callback(data);
  };
  useEffect(() => {
    if (chatRequestType === 'ws') {
      wsRequestRef.current =
        wsRequest && wsRequest({ addMessageList, upDateMessageItem });
    }
    return () => {
      if (wsRequestRef.current) {
        wsRequestRef.current.close();
        wsRequestRef.current = undefined;
      }
    };
  }, [chatRequestType]);
  return (
    <ChatContext.Provider
      value={{
        messagesList: state,
        chatRequestType,
        sendMessage,
        addMessageList,
        upDateMessageItem,
        removeMessageList,
        setChatRequestType,
        getMessageItem,
        setMessageList,
        handleRequest,
      }}
    >
      {children}
    </ChatContext.Provider>
  );
};
