export function MessageInput({
  room,
  scrollToMessage,
  newMessagePacks,
  updateMessagePacks,
}: {
  room: RoomType
  scrollToMessage: (messageId: string) => void
  newMessagePacks: (messagePack: MessagePackType) => void
  updateMessagePacks: (messagePack: MessagePackType) => void
}) {
  // ---------------------------------------------------------------------------
  // variables
  // ---------------------------------------------------------------------------

  const styles = useStyles()
  const modal = useModal()
  const accountId = useAccountId()
  const insets = useSafeAreaInsets()
  const dimensions = useWindowDimensions()
  const currentRoomUISettings = useCurrentRoomUISettings(room.id)
  const [messagePacks, setMessagePacks] = useState<MessagePackType[]>([])
  const quoteMessage = currentRoomUISettings.quotedMessage
  const editMessage = currentRoomUISettings.editMessage
  const screenHeight = dimensions.height

  const { channel, communityId } = useRoomMetadata(room.id)

  const members = useMembersBy({ communityId: communityId })
  const userProfiles = useUserProfiles({
    in: members.map((member) => member.identityId),
  })
  const channels = useChannelsBy({ communityId: communityId })
  const [filteredUsers, setFilteredUsers] = useState<UserType[]>([])
  const [filteredChannels, setFilteredChannels] = useState<ChannelType[]>([])
  const [newInputHeight, setNewInputHeight] = useState(0)
  const [isShowEmojiBox, setIsShowEmojiBox] = useState(false)
  const [maxShowEmoji, setMaxShowEmoji] = useState(false)
  const [expanded, setExpanded] = useState(false)
  const [attachmentKind, setAttachmentKind] = useState<AttachmentKindEnum>()
  const [textMessage, setTextMessage] = useState<string>("")
  const [editTextMessage, setEditTextMessage] = useState<string>("")

  const [editMessageInput, setEditMessageInput] = useState<MessageType | null>()
  const [files, setFiles] = useState<FileType[]>([])
  const [messageLinks, setMessageLinks] = useState<LinkPreviewType[]>([])
  const [linkIgnoreList, setLinkIgnoreList] = useState([""])
  const [emotionCategory, setEmotionCategory] =
    useState<EmotionCategoryType>("emoji")
  const [currentType, setCurrentType] = useState<
    "emoji" | "keyboard" | "sticker" | "gif"
  >("keyboard")
  const [deviceState, setDeviceState] = useState({
    camera: false,
    microphone: false,
  })
  const [deviceActiveState, setDeviceActiveState] = useState({
    cameraActive: false,
    microphoneActive: false,
  })
  const [selection, setSelection] = useState({
    start: 0,
    end: 0,
  })
  const [showTools, setShowTools] = useState(false)
  const [selectedToolbarIcon, setSelectedToolbarIcon] = useState<
    "bold" | "italic" | "strikethrough" | "code" | "bulletList" | "orderedList"
  >("bold")
  const [toggleMarkdownList, setToggleMarkdownList] = useState("")
  const [slowModeTime, setSlowModeTime] = useState(0)

  const inputRef = useRef<TextInput | null>(null)
  const inputWrapperRef = useRef<View>(null)
  const slowModeInterval = useRef<NodeJS.Timeout>()

  // ---------------------------------------------------------------------------
  // animations
  // ---------------------------------------------------------------------------

  const inputHeight = useSharedValue(newInputHeight)

  const animatedInputStyles = useAnimatedStyle(() => ({
    height: maxShowEmoji ? inputHeight.value : "auto",
  }))
  const animatedEmojiStyles = useAnimatedStyle(() =>
    maxShowEmoji
      ? { height: "auto" }
      : isShowEmojiBox
        ? {
            height: 320,
          }
        : {},
  )

  // ---------------------------------------------------------------------------
  // effects
  // ---------------------------------------------------------------------------

  useEffect(() => {
    if (channel && channel.slowMode) {
      const lastMessageSendTime = room.lastMessageSendTime
      const slowMode = channel ? channel.slowMode : 0

      slowModeInterval.current = setInterval(() => {
        const timeLeft =
          slowMode - Math.floor((Date.now() - lastMessageSendTime) / 1000)

        if (timeLeft < 0) {
          clearInterval(slowModeInterval.current)
          setSlowModeTime(timeLeft)
        } else {
          setSlowModeTime(timeLeft)
        }
      }, 1000)
    }
    return () => {
      clearInterval(slowModeInterval.current)
    }
  }, [room.lastMessageSendTime])

  useEffect(() => {
    loadDraft()
  }, [room.id])

  useEffect(() => {
    setEditMessageInput(editMessage)

    if (editMessage) setEditTextMessage(editMessage.text)
  }, [editMessage])

  useEffect(() => {
    if (!files.length) return

    onMessageTyping(textMessage)
  }, [files.length])

  // ---------------------------------------------------------------------------
  // functions
  // ---------------------------------------------------------------------------

  function goDown() {
    inputHeight.value = withTiming(newInputHeight, {
      duration: 0,
      easing: Easing.inOut(Easing.quad),
      reduceMotion: ReduceMotion.System,
    })

    setMaxShowEmoji(false)
    setExpanded(false)
  }

  function goUp() {
    if (!inputWrapperRef.current) return

    inputWrapperRef.current.measure((x, y, width, height, pageX, pageY) => {
      setNewInputHeight(height)
    })

    setTimeout(() => setMaxShowEmoji(true), 0)

    inputHeight.value = withTiming(
      screenHeight - insets.top - insets.bottom - 20,
      {
        duration: 0,
        easing: Easing.inOut(Easing.quad),
        reduceMotion: ReduceMotion.System,
      },
    )

    setExpanded(true)
  }

  async function sendMessage(
    kind: MessageKindEnum,
    messageText: string,
    mediaFile: FileType[],
    sticker?: { sticker: StickerType; stickerPackId: string },
    user?: {
      id: string
      name: string
      photo: FileType | null
    },
  ) {
    if (!accountId || !currentRoomUISettings) return

    if (channel && channel.slowMode) {
      if (Date.now() - room.lastMessageSendTime > channel.slowMode * 1000) {
        await AppController.room.update({
          id: room.id,
          lastMessageSendTime: Date.now(),
        })
      } else {
        return
      }
    }

    let attachments: AttachmentType[] = []

    for (let file of mediaFile) {
      if (!attachmentKind) return
      const attachment: AttachmentType = {
        id: RandomUtils.uuid(),
        createdAt: Date.now(),
        kind: attachmentKind,
        name: file.name,
        size: file.size,
        roomId: room.id,
        messageId: null,
        senderId: accountId,
        mimeType:
          kind === MessageKindEnum.audio
            ? "audio-record"
            : kind === MessageKindEnum.video
              ? "video-record"
              : file.mimeType.startsWith("application")
                ? file.mimeType.split("/")[1]
                : file.mimeType.split("/")[0],
        preview: file.data,
        fileId: file.id,
      }

      attachments.push(attachment)
    }

    let links: LinkType[] = []
    for (let messageLink of messageLinks) {
      const link: LinkType = {
        id: RandomUtils.uuid(),
        createdAt: Date.now(),
        roomId: room.id,
        ...messageLink,
      }

      links.push(link)
    }

    const metadata: MessageMetadataType = {
      id: RandomUtils.uuid(),
      replyCount: 0,
    }

    const message: MessageType = {
      id: RandomUtils.uuid(),
      createdAt: Date.now(),
      text: messageText,
      roomId: room.id,
      isEdited: false,
      isDeleted: false,
      isDelivered: false,
      senderId: accountId,
      reactions: [],
      forward: null,
      regular: {
        kind: kind,
        quote: quoteMessage ? quoteMessage : null,
        sharedUser: user ? user : null,
        sticker: sticker ? sticker : null,
      },
      question: null,
      answer:
        room.kind === RoomKindEnum.QUESTION_ANSWERS
          ? {
              negativeVotes: [],
              positiveVotes: [],
            }
          : null,
      news: null,
      issue: null,
      board: null,
    }

    newMessagePacks({
      message,
      metadata,
      links,
      attachments,
      files: [],
      poll: undefined,
    })

    await AppController.message.insert([
      {
        links,
        message,
        metadata,
        attachments,
        files: mediaFile,
        poll: undefined,
      },
    ])

    AppStore.for(CurrentRoomUISettingsModel).set([
      {
        ...currentRoomUISettings,
        quotedMessage: undefined,
      },
    ])
    MessageTextAreaUtils.setDraft(room.id, null, room.draftMessage)

    setTextMessage("")

    await TrackPlayer.add({
      id: "send",
      url: require("../../../../public/sounds/message_send.wav"),
      title: "Track Title",
      artist: "Track Artist",
    })

    // Start playing it
    await TrackPlayer.play()
    removeAttachedData()
  }

  async function onMessageUpdate(
    editedMessage: MessageType,
    attachments: AttachmentType[],
    files: FileType[],
    poll?: PollType,
  ) {
    await AppController.message.update({
      roomId: editedMessage.roomId,
      messageId: editedMessage.id,
      message: editedMessage,
      files,
      attachments,
      poll,
    })
    const oldMessagePack = messagePacks.find(
      (oldMessagePack) => oldMessagePack.message.id === editedMessage.id,
    )
    if (oldMessagePack) {
      const updatedMessages = Mutator.replace(messagePacks, oldMessagePack, {
        ...oldMessagePack,
        message: editedMessage,
        attachments,
      })
      updateMessagePacks(updatedMessages)
      setMessagePacks(updatedMessages)
    }
  }
 updateMessagePacks(updatedMessages) - Argument of type '{ message: MessageType; attachments: AttachmentType[]; metadata: MessageMetadataType; links: LinkType[]; files: FileType[]; poll: PollType | undefined; }[]' is not assignable to parameter of type 'MessagePackType'.
  Type '{ message: MessageType; attachments: AttachmentType[]; metadata: MessageMetadataType; links: LinkType[]; files: FileType[]; poll: PollType | undefined; }[]' is missing the following properties from type 'MessagePackType': message, metadata, attachments, links, and 2 more.ts(2345)