import type { Session } from '@botonic/core'
import { useReducer, useRef } from 'react'

import type { Reply } from '../../components'
import type { Webview } from '../../components/index-types'
import type { WebchatMessage } from '../../index-types'
import { defaultTheme } from '../theme/default-theme'
import type { WebchatTheme } from '../theme/types'
import { WebchatAction } from './actions'
import type {
  ClientInput,
  DevSettings,
  ErrorMessage,
  WebchatState,
} from './types'
import { webchatReducer } from './webchat-reducer'

function getWebchatInitialState(initialTheme: WebchatTheme): WebchatState {
  return {
    replies: [],
    messagesJSON: [],
    messagesComponents: [],
    latestInput: {},
    typing: false,
    webview: undefined,
    webviewParams: undefined,
    session: { user: undefined },
    lastRoutePath: undefined,
    handoff: false,
    theme: initialTheme,
    themeUpdates: {},
    error: {},
    online: true,
    devSettings: { keepSessionOnReload: false },
    isWebchatOpen: false,
    isEmojiPickerOpen: false,
    isPersistentMenuOpen: false,
    isCoverComponentOpen: false,
    isCustomComponentRendered: false,
    lastMessageUpdate: undefined,
    currentAttachment: undefined,
    numUnreadMessages: 0,
    isLastMessageVisible: true,
    isInputFocused: false,
  }
}

export interface UseWebchat {
  addMessage: (message: WebchatMessage) => void
  addMessageComponent: (message: { props: WebchatMessage }) => void
  clearMessages: () => void
  doRenderCustomComponent: (toggle: boolean) => void
  resetUnreadMessages: () => void
  setCurrentAttachment: (attachment?: File) => void
  setError: (error?: ErrorMessage) => void
  setIsInputFocused: (isInputFocused: boolean) => void
  setLastMessageVisible: (isLastMessageVisible: boolean) => void
  setOnline: (online: boolean) => void
  toggleCoverComponent: (toggle: boolean) => void
  toggleEmojiPicker: (toggle: boolean) => void
  togglePersistentMenu: (toggle: boolean) => void
  toggleWebchat: (toggle: boolean) => void
  updateCustomMessageProps: (
    props: Record<string, any>,
    messageId?: string
  ) => void
  updateDevSettings: (settings: DevSettings) => void
  updateHandoff: (handoff: boolean) => void
  updateLastMessageDate: (date: string) => void
  updateLastRoutePath: (path: string) => void
  updateLatestInput: (input: ClientInput) => void
  updateMessage: (message: WebchatMessage) => void
  updateReplies: (replies: (typeof Reply)[]) => void
  updateSession: (session: Partial<Session>) => void
  updateTheme: (theme: WebchatTheme, themeUpdates?: WebchatTheme) => void
  updateTyping: (typing: boolean) => void
  updateWebview: (webview: Webview, params: Record<string, string>) => void
  removeReplies: () => void
  removeWebview: () => void
  webchatState: WebchatState
  webchatContainerRef: React.MutableRefObject<HTMLDivElement | null>
  headerRef: React.MutableRefObject<HTMLDivElement | null>
  chatAreaRef: React.MutableRefObject<HTMLDivElement | null>
  scrollableMessagesListRef: React.MutableRefObject<HTMLDivElement | null>
  repliesRef: React.MutableRefObject<HTMLDivElement | null>
  inputPanelRef: React.MutableRefObject<HTMLDivElement | null>
}

export function useWebchat(theme?: WebchatTheme): UseWebchat {
  const initialTheme = theme || defaultTheme
  const webchatInitialState = getWebchatInitialState(initialTheme)

  const [webchatState, webchatDispatch] = useReducer(
    webchatReducer,
    webchatInitialState
  )

  const webchatContainerRef = useRef<HTMLDivElement | null>(null)
  const chatAreaRef = useRef<HTMLDivElement | null>(null)
  const inputPanelRef = useRef<HTMLDivElement | null>(null)
  const headerRef = useRef<HTMLDivElement | null>(null)
  const scrollableMessagesListRef = useRef<HTMLDivElement | null>(null)
  const repliesRef = useRef<HTMLDivElement | null>(null)

  const addMessage = (message: WebchatMessage) =>
    webchatDispatch({ type: WebchatAction.ADD_MESSAGE, payload: message })

  const addMessageComponent = (message: { props: WebchatMessage }) =>
    webchatDispatch({
      type: WebchatAction.ADD_MESSAGE_COMPONENT,
      payload: message,
    })

  const updateCustomMessageProps = (
    props: Record<string, any>,
    messageId?: string
  ) =>
    webchatDispatch({
      type: WebchatAction.UPDATE_CUSTOM_MESSAGE_PROPS,
      payload: { messageId, props },
    })

  const updateMessage = (message: WebchatMessage) =>
    webchatDispatch({ type: WebchatAction.UPDATE_MESSAGE, payload: message })

  const updateReplies = (replies: (typeof Reply)[]) =>
    webchatDispatch({ type: WebchatAction.UPDATE_REPLIES, payload: replies })

  const removeReplies = () =>
    webchatDispatch({ type: WebchatAction.REMOVE_REPLIES, payload: [] })

  const updateLatestInput = (input: ClientInput) =>
    webchatDispatch({ type: WebchatAction.UPDATE_LATEST_INPUT, payload: input })

  const updateTyping = (typing: boolean) =>
    webchatDispatch({ type: WebchatAction.UPDATE_TYPING, payload: typing })

  const updateWebview = (webview: Webview, params: Record<string, string>) =>
    webchatDispatch({
      type: WebchatAction.UPDATE_WEBVIEW,
      payload: { webview, webviewParams: params },
    })

  const removeWebview = () =>
    webchatDispatch({
      type: WebchatAction.REMOVE_WEBVIEW,
    })

  const updateSession = (session: Partial<Session>) => {
    webchatDispatch({
      type: WebchatAction.UPDATE_SESSION,
      payload: session,
    })
  }

  const updateLastRoutePath = (path: string) =>
    webchatDispatch({
      type: WebchatAction.UPDATE_LAST_ROUTE_PATH,
      payload: path,
    })

  const updateHandoff = (handoff: boolean) =>
    webchatDispatch({
      type: WebchatAction.UPDATE_HANDOFF,
      payload: handoff,
    })

  const updateTheme = (theme: WebchatTheme, themeUpdates?: WebchatTheme) => {
    const payload =
      themeUpdates !== undefined ? { theme, themeUpdates } : { theme }
    webchatDispatch({
      type: WebchatAction.UPDATE_THEME,
      payload,
    })
  }

  const updateDevSettings = (settings: DevSettings) =>
    webchatDispatch({
      type: WebchatAction.UPDATE_DEV_SETTINGS,
      payload: settings,
    })

  const toggleWebchat = (toggle: boolean) => {
    webchatDispatch({
      type: WebchatAction.TOGGLE_WEBCHAT,
      payload: toggle,
    })
  }

  const toggleEmojiPicker = (toggle: boolean) =>
    webchatDispatch({
      type: WebchatAction.TOGGLE_EMOJI_PICKER,
      payload: toggle,
    })

  const togglePersistentMenu = (toggle: boolean) =>
    webchatDispatch({
      type: WebchatAction.TOGGLE_PERSISTENT_MENU,
      payload: toggle,
    })

  const toggleCoverComponent = (toggle: boolean) =>
    webchatDispatch({
      type: WebchatAction.TOGGLE_COVER_COMPONENT,
      payload: toggle,
    })

  const doRenderCustomComponent = (toggle: boolean) =>
    webchatDispatch({
      type: WebchatAction.DO_RENDER_CUSTOM_COMPONENT,
      payload: toggle,
    })

  const setError = (error?: ErrorMessage) =>
    webchatDispatch({
      type: WebchatAction.SET_ERROR,
      payload: error,
    })

  const setOnline = (online: boolean) =>
    webchatDispatch({
      type: WebchatAction.SET_ONLINE,
      payload: online,
    })

  const clearMessages = () => {
    webchatDispatch({
      type: WebchatAction.CLEAR_MESSAGES,
    })
  }

  const updateLastMessageDate = (date: string) => {
    webchatDispatch({
      type: WebchatAction.UPDATE_LAST_MESSAGE_DATE,
      payload: date,
    })
  }

  const setCurrentAttachment = (attachment?: File) => {
    webchatDispatch({
      type: WebchatAction.SET_CURRENT_ATTACHMENT,
      payload: attachment,
    })
  }

  const resetUnreadMessages = () => {
    webchatDispatch({
      type: WebchatAction.RESET_UNREAD_MESSAGES,
    })
  }

  const setLastMessageVisible = (isLastMessageVisible: boolean) => {
    webchatDispatch({
      type: WebchatAction.SET_LAST_MESSAGE_VISIBLE,
      payload: isLastMessageVisible,
    })
  }

  const setIsInputFocused = (isInputFocused: boolean) => {
    webchatDispatch({
      type: WebchatAction.SET_IS_INPUT_FOCUSED,
      payload: isInputFocused,
    })
  }

  return {
    addMessage,
    addMessageComponent,
    clearMessages,
    doRenderCustomComponent,
    resetUnreadMessages,
    setCurrentAttachment,
    setError,
    setIsInputFocused,
    setLastMessageVisible,
    setOnline,
    toggleCoverComponent,
    toggleEmojiPicker,
    togglePersistentMenu,
    toggleWebchat,
    updateCustomMessageProps,
    updateDevSettings,
    updateHandoff,
    updateLastMessageDate,
    updateLastRoutePath,
    updateLatestInput,
    updateMessage,
    updateReplies,
    updateSession,
    updateTheme,
    updateTyping,
    updateWebview,
    removeReplies,
    removeWebview,
    webchatState,
    webchatContainerRef,
    headerRef,
    chatAreaRef,
    scrollableMessagesListRef,
    repliesRef,
    inputPanelRef,
  }
}
