import {
  CheckOutlined,
  DeleteOutlined,
  LeftOutlined,
  PlusOutlined,
  RightOutlined,
  SaveOutlined,
  UnorderedListOutlined,
} from '@ant-design/icons';
import { Button, Empty, Input, Modal, Splitter, message } from 'antd';
import { useEffect, useMemo, useState } from 'react';
import { renderModalWithEnterConfirm } from '../../../app/main/modalKeyboard';
import { InputUI } from '../../../components/inputs/primitives/input';
import {
  createTextMemoNote,
  deleteTextMemoNote,
  fetchTextMemoNotes,
  updateTextMemoNote,
  type TextMemoNoteRecord,
} from '../../../widgets/text-memo-widget/textMemoApi';
import './MemoLayoutPage.css';

type MemoLayoutPageProps = {
  layoutId: string;
};

type MemoNote = TextMemoNoteRecord;

const PRIMARY_SIZE = '42%';
const PRIMARY_MIN = '24%';
const SECONDARY_MIN = '20%';
const MAX_NOTE_COUNT = 12;
const MAX_BODY_LENGTH = 1200;

function getFirstLine(value: string) {
  const [firstLine = ''] = value.split(/\r?\n/u);
  return firstLine;
}

function replaceFirstLine(body: string, nextTitle: string) {
  const normalizedTitle = nextTitle.trim();
  const lineBreakIndex = body.search(/\r?\n/u);

  if (lineBreakIndex < 0) {
    return normalizedTitle;
  }

  const nextTail = body.slice(lineBreakIndex);
  return `${normalizedTitle}${nextTail}`;
}

function getPreviewText(body: string) {
  const preview = body.replace(/\s+/gu, ' ').trim();
  return preview || '새 메모';
}

function formatMemoTimestamp(value: string) {
  return new Intl.DateTimeFormat('ko-KR', {
    month: 'short',
    day: 'numeric',
    hour: 'numeric',
    minute: '2-digit',
  }).format(new Date(value));
}

export function MemoLayoutPage({ layoutId }: MemoLayoutPageProps) {
  const [messageApi, contextHolder] = message.useMessage();
  const [modalApi, modalContextHolder] = Modal.useModal();
  const [notes, setNotes] = useState<MemoNote[]>([]);
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [body, setBody] = useState('');
  const [isListOpen, setIsListOpen] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [isSaving, setIsSaving] = useState(false);

  useEffect(() => {
    let cancelled = false;

    void (async () => {
      setIsLoading(true);

      try {
        const items = await fetchTextMemoNotes();

        if (cancelled) {
          return;
        }

        setNotes(items);

        if (items[0]) {
          setSelectedId(items[0].id);
          setBody(items[0].body);
        } else {
          setSelectedId(null);
          setBody('');
        }
      } catch (error) {
        if (!cancelled) {
          void messageApi.error(error instanceof Error ? error.message : '메모를 불러오지 못했습니다.');
        }
      } finally {
        if (!cancelled) {
          setIsLoading(false);
        }
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [messageApi]);

  const selectedIndex = useMemo(
    () => (selectedId ? notes.findIndex((note) => note.id === selectedId) : -1),
    [notes, selectedId],
  );
  const selectedNote = selectedIndex >= 0 ? notes[selectedIndex] : null;
  const inputValue = getFirstLine(body);
  const hasDraft = body.trim().length > 0;
  const isDirty = selectedNote ? selectedNote.body !== body : hasDraft;

  const selectNote = (noteId: string) => {
    const nextNote = notes.find((item) => item.id === noteId);

    if (!nextNote) {
      return;
    }

    setSelectedId(nextNote.id);
    setBody(nextNote.body);
  };

  const moveSelection = (direction: -1 | 1) => {
    if (notes.length === 0) {
      return;
    }

    const fallbackIndex = direction > 0 ? 0 : notes.length - 1;
    const nextIndex = selectedIndex < 0 ? fallbackIndex : (selectedIndex + direction + notes.length) % notes.length;
    const nextNote = notes[nextIndex];

    if (!nextNote) {
      return;
    }

    setSelectedId(nextNote.id);
    setBody(nextNote.body);
  };

  const handleCreate = () => {
    setSelectedId(null);
    setBody('');
    setIsListOpen(false);
  };

  const handleSave = async () => {
    const trimmedBody = body.trim();

    if (!trimmedBody || isSaving) {
      return;
    }

    setIsSaving(true);

    try {
      if (selectedNote) {
        const updated = await updateTextMemoNote(selectedNote.id, { body: trimmedBody });
        const nextNotes = [updated, ...notes.filter((note) => note.id !== updated.id)].slice(0, MAX_NOTE_COUNT);

        setNotes(nextNotes);
        setSelectedId(updated.id);
        setBody(updated.body);
      } else {
        const created = await createTextMemoNote({ body: trimmedBody });
        const nextNotes = [created, ...notes].slice(0, MAX_NOTE_COUNT);

        setNotes(nextNotes);
        setSelectedId(created.id);
        setBody(created.body);
      }

      void messageApi.success('저장됨');
    } catch (error) {
      void messageApi.error(error instanceof Error ? error.message : '메모 저장에 실패했습니다.');
    } finally {
      setIsSaving(false);
    }
  };

  const handleDelete = () => {
    if (!selectedNote && !hasDraft) {
      return;
    }

    void modalApi.confirm({
      title: selectedNote ? '선택한 메모를 삭제할까요?' : '작성 중인 메모를 삭제할까요?',
      content: selectedNote ? '삭제 후 되돌릴 수 없습니다.' : '작성 중인 내용이 사라집니다.',
      okText: '삭제',
      cancelText: '취소',
      autoFocusButton: 'ok',
      modalRender: renderModalWithEnterConfirm,
      okButtonProps: { danger: true },
      async onOk() {
        if (!selectedNote) {
          setBody('');
          return;
        }

        await deleteTextMemoNote(selectedNote.id);
        const nextNotes = notes.filter((note) => note.id !== selectedNote.id);
        const fallbackNote = nextNotes[0] ?? null;

        setNotes(nextNotes);
        setSelectedId(fallbackNote?.id ?? null);
        setBody(fallbackNote?.body ?? '');
        void messageApi.success('삭제됨');
      },
    });
  };

  return (
    <div className="memo-layout-page" data-layout-id={layoutId}>
      {contextHolder}
      {modalContextHolder}
      <Splitter layout="vertical" className="memo-layout-page__splitter">
        <Splitter.Panel size={PRIMARY_SIZE} min={PRIMARY_MIN} resizable>
          <section className="memo-layout-page__pane memo-layout-page__pane--title">
            <InputUI
              value={inputValue}
              placeholder="제목"
              className="memo-layout-page__title-input"
              onChange={(event) => {
                const nextValue = event.target.value.slice(0, MAX_BODY_LENGTH);
                setBody((previousBody) => replaceFirstLine(previousBody, nextValue));
              }}
            />
          </section>
        </Splitter.Panel>
        <Splitter.Panel min={SECONDARY_MIN} resizable>
          <section className="memo-layout-page__pane memo-layout-page__pane--memo">
            <div className="memo-layout-page__toolbar" role="toolbar" aria-label="메모 도구">
              <div className="memo-layout-page__toolbar-group">
                <Button type="text" aria-label="새 메모" icon={<PlusOutlined />} onClick={handleCreate} />
                <Button
                  type={isListOpen ? 'default' : 'text'}
                  aria-label="메모 목록"
                  icon={<UnorderedListOutlined />}
                  onClick={() => {
                    setIsListOpen((previous) => !previous);
                  }}
                />
                <Button
                  type="text"
                  aria-label="이전 메모"
                  icon={<LeftOutlined />}
                  disabled={notes.length === 0}
                  onClick={() => {
                    moveSelection(-1);
                  }}
                />
                <Button
                  type="text"
                  aria-label="다음 메모"
                  icon={<RightOutlined />}
                  disabled={notes.length === 0}
                  onClick={() => {
                    moveSelection(1);
                  }}
                />
              </div>
              <div className="memo-layout-page__toolbar-group">
                <Button
                  type="text"
                  aria-label="삭제"
                  icon={<DeleteOutlined />}
                  disabled={!selectedNote && !hasDraft}
                  onClick={handleDelete}
                />
                <Button
                  type="text"
                  aria-label="저장"
                  icon={isDirty ? <SaveOutlined /> : <CheckOutlined />}
                  disabled={!hasDraft || isSaving || !isDirty}
                  onClick={() => {
                    void handleSave();
                  }}
                />
              </div>
            </div>

            <div className={`memo-layout-page__body${isListOpen ? ' memo-layout-page__body--list-open' : ''}`}>
              {isListOpen ? (
                <div className="memo-layout-page__list-shell">
                  {notes.length === 0 ? (
                    <div className="memo-layout-page__empty">
                      <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={false} />
                    </div>
                  ) : (
                    <div className="memo-layout-page__list">
                      {notes.map((note) => (
                        <button
                          key={note.id}
                          type="button"
                          className={`memo-layout-page__list-item${
                            note.id === selectedId ? ' memo-layout-page__list-item--active' : ''
                          }`}
                          onClick={() => {
                            selectNote(note.id);
                            setIsListOpen(false);
                          }}
                        >
                          <span className="memo-layout-page__list-time">{formatMemoTimestamp(note.updatedAt)}</span>
                          <span className="memo-layout-page__list-preview">{getPreviewText(note.body)}</span>
                        </button>
                      ))}
                    </div>
                  )}
                </div>
              ) : null}

              <div className="memo-layout-page__editor">
                <div className="memo-layout-page__meta">
                  <span>{selectedNote ? formatMemoTimestamp(selectedNote.updatedAt) : ''}</span>
                  <span>{body.length}/{MAX_BODY_LENGTH}</span>
                </div>
                <Input.TextArea
                  value={body}
                  placeholder="메모 입력"
                  className="memo-layout-page__textarea"
                  autoSize={false}
                  disabled={isLoading}
                  maxLength={MAX_BODY_LENGTH}
                  onChange={(event) => {
                    setBody(event.target.value);
                  }}
                />
              </div>
            </div>
          </section>
        </Splitter.Panel>
      </Splitter>
    </div>
  );
}
