import React, { FormEventHandler, KeyboardEventHandler, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { isKeyHotkey } from 'is-hotkey';
import FocusTrap from 'focus-trap-react';
import { Box, Button, Header, IconButton, Modal, Overlay, OverlayBackdrop, OverlayCenter, Line, Scroll, Text, color, config, toRem } from 'folds';
import { Icon, Icons } from '../../components/icons';
import {
  CustomEditor,
  Toolbar,
  isEmptyEditor,
  resetEditor,
  resetEditorHistory,
  toMatrixCustomHTML,
  toPlainText,
  trimCustomHtml,
  useEditor,
} from '../../components/editor';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { stopPropagation } from '../../utils/keyboard';
import { sendForumPost, sendForumMediaRoot, sendForumThreadAttachment } from './forumFeed';
import { FORUM_EDITOR_OUTPUT_OPTS } from './forumRichText';
import type { ForumPublishedPost, ForumSection } from './types';
import { ForumTopicTargetFields } from './ForumTopicTargetFields';
import { ForumPostUploadField, useForumPostUploads } from './ForumPostUploadField';
import * as t from './forumTheme.css';

type ForumNewPostModalProps = {
  sections: ForumSection[];
  initialCategory?: string;
  initialTopicRoomId?: string;
  onClose: () => void;
  onPublished?: (published: ForumPublishedPost) => void;
};

export function ForumNewPostModal({
  sections,
  initialCategory = '',
  initialTopicRoomId = '',
  onClose,
  onPublished,
}: ForumNewPostModalProps) {
  const mx = useMatrixClient();
  const editor = useEditor();
  const formRef = useRef<HTMLFormElement>(null);
  const [title, setTitle] = useState('');
  const [category, setCategory] = useState(initialCategory);
  const [topicRoomId, setTopicRoomId] = useState(initialTopicRoomId);
  const [sending, setSending] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const uploadRoomKey = topicRoomId || '__forum_new_post_draft__';
  const {
    selectedFiles,
    uploadBoardHandlers,
    handleUploadsReady,
    collectUploadContents,
    clearUploads,
  } = useForumPostUploads(uploadRoomKey);

  const categoryTopics = useMemo(() => {
    if (category) {
      return sections.find((s) => s.title === category)?.topics ?? [];
    }
    return sections.flatMap((s) => s.topics);
  }, [category, sections]);

  useEffect(() => {
    if (!topicRoomId) return;
    if (!categoryTopics.some((topic) => topic.roomId === topicRoomId)) {
      setTopicRoomId('');
    }
  }, [categoryTopics, topicRoomId]);

  const handleClose = useCallback(() => {
    if (sending) return;
    resetEditor(editor);
    resetEditorHistory(editor);
    clearUploads();
    onClose();
  }, [clearUploads, editor, onClose, sending]);

  const handleSubmit: FormEventHandler<HTMLFormElement> = useCallback(
    async (evt) => {
      evt.preventDefault();
      if (sending) return;

      const trimmedTitle = title.trim();
      const plainText = toPlainText(editor.children, false).trim();
      const formattedHtml = trimCustomHtml(
        toMatrixCustomHTML(editor.children, FORUM_EDITOR_OUTPUT_OPTS)
      );

      const hasText = !isEmptyEditor(editor);
      const hasUploads = selectedFiles.length > 0;

      if (!topicRoomId) {
        setError('Select a topic for this post.');
        return;
      }
      if (!trimmedTitle) {
        setError('Post title is required.');
        return;
      }
      if (!hasText && !hasUploads) {
        setError('Post body or an attachment is required.');
        return;
      }

      setSending(true);
      setError(null);
      try {
        const attachmentContents = hasUploads ? await collectUploadContents() : [];
        let eventId: string;
        let publishedPlainText = plainText;
        let publishedHtml = formattedHtml;

        if (hasText) {
          eventId = await sendForumPost(mx, topicRoomId, {
            title: trimmedTitle,
            plainText,
            formattedHtml,
          });
        } else {
          const [first, ...rest] = attachmentContents;
          if (!first) {
            throw new Error('Attachments failed to upload.');
          }
          eventId = await sendForumMediaRoot(mx, topicRoomId, trimmedTitle, first);
          publishedPlainText = typeof first.body === 'string' ? first.body : trimmedTitle;
          publishedHtml = '';
          for (const content of rest) {
            await sendForumThreadAttachment(mx, topicRoomId, eventId, content);
          }
        }

        if (hasText) {
          for (const content of attachmentContents) {
            await sendForumThreadAttachment(mx, topicRoomId, eventId, content);
          }
        }

        resetEditor(editor);
        resetEditorHistory(editor);
        clearUploads();
        onPublished?.({
          eventId,
          topicRoomId,
          title: trimmedTitle,
          plainText: publishedPlainText,
          formattedHtml: publishedHtml,
        });
        onClose();
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Failed to publish post');
      } finally {
        setSending(false);
      }
    },
    [
      clearUploads,
      collectUploadContents,
      editor,
      mx,
      onClose,
      onPublished,
      selectedFiles.length,
      sending,
      title,
      topicRoomId,
    ]
  );

  const handleEditorKeyDown: KeyboardEventHandler = useCallback(
    (evt) => {
      if (isKeyHotkey('mod+enter', evt) && !sending) {
        evt.preventDefault();
        evt.currentTarget.closest('form')?.requestSubmit();
      }
    },
    [sending]
  );

  const handleCategoryChange = useCallback((next: string) => {
    setCategory(next);
    setTopicRoomId('');
  }, []);

  return (
    <Overlay open backdrop={<OverlayBackdrop />}>
      <OverlayCenter>
        <FocusTrap
          focusTrapOptions={{
            initialFocus: false,
            onDeactivate: handleClose,
            clickOutsideDeactivates: !sending,
            escapeDeactivates: stopPropagation,
          }}
        >
          <Modal
            size="500"
            style={{
              display: 'flex',
              flexDirection: 'column',
              maxHeight: 'min(90vh, 52rem)',
              maxWidth: 'min(720px, calc(100vw - 2rem))',
              width: '100%',
            }}
          >
            <Header
              size="500"
              style={{
                padding: config.space.S300,
                paddingLeft: config.space.S400,
                borderBottomWidth: config.borderWidth.B300,
              }}
            >
              <Box grow="Yes">
                <Text size="H4">New post</Text>
              </Box>
              <IconButton size="300" radii="300" onClick={handleClose} disabled={sending} aria-label="Close">
                <Icon src={Icons.Cross} />
              </IconButton>
            </Header>
            <Scroll size="300" hideTrack style={{ flex: '1 1 auto', minHeight: 0 }}>
              <Box
                as="form"
                ref={formRef}
                className={t.ForumPostModalForm}
                onSubmit={handleSubmit}
                direction="Column"
                style={{ padding: config.space.S400 }}
              >
                <ForumTopicTargetFields
                  sections={sections}
                  category={category}
                  topicRoomId={topicRoomId}
                  onCategoryChange={handleCategoryChange}
                  onTopicChange={setTopicRoomId}
                  disabled={sending}
                />

                <input
                  id="forum-post-title"
                  className={t.ForumFilterSelect}
                  name="title"
                  type="text"
                  value={title}
                  onChange={(e) => setTitle(e.target.value)}
                  maxLength={140}
                  required
                  autoFocus
                  placeholder="Title"
                  aria-label="Title"
                  autoComplete="off"
                  disabled={sending}
                />

                <Box className={t.ForumPostModalBodyField}>
                  <Box className={t.ForumPostModalEditorWrap}>
                    <CustomEditor
                      editor={editor}
                      fillHeight
                      placeholder="Write your post…"
                      maxHeight={toRem(280)}
                      onKeyDown={handleEditorKeyDown}
                      bottom={
                        <div>
                          <Line variant="SurfaceVariant" size="300" />
                          <Box alignItems="Center" gap="200" style={{ padding: `0 ${config.space.S200}` }}>
                            <ForumPostUploadField
                              roomId={uploadRoomKey}
                              disabled={sending || !topicRoomId}
                              uploadBoardHandlers={uploadBoardHandlers}
                              onUploadsReady={handleUploadsReady}
                            />
                            <Box grow="Yes" />
                            <Toolbar />
                          </Box>
                        </div>
                      }
                    />
                  </Box>
                </Box>

                {error && (
                  <Text size="T200" style={{ color: color.Critical.Main }}>
                    {error}
                  </Text>
                )}

                <Box className={t.ForumPostModalActions}>
                  <Button
                    type="button"
                    variant="SurfaceVariant"
                    size="400"
                    radii="300"
                    onClick={handleClose}
                    disabled={sending}
                  >
                    <Text size="B400">Cancel</Text>
                  </Button>
                  <Button type="submit" variant="Primary" size="400" radii="300" disabled={sending}>
                    <Text size="B400">{sending ? 'Publishing…' : 'Publish post'}</Text>
                  </Button>
                </Box>
              </Box>
            </Scroll>
          </Modal>
        </FocusTrap>
      </OverlayCenter>
    </Overlay>
  );
}
