'use client';

/**
 * @author: Kim Jino
 * @since: 2025.03.31
 * @description: CKEditor component for Next.js using Script component for loading CKEditor script
 */

// @/app/(forum)/post/_component/Editor.tsx

import '@/styles/editor.scss';
import Script from 'next/script';
import React, { useRef, useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { CKEditor } from '@ckeditor/ckeditor5-react';
import type { Editor as CKEditorInstance } from '@ckeditor/ckeditor5-core';
import Loading from '@/app/component/Loading';
import BoardMeta from '@/types/forum/boardMeta';
import { PostConst } from '@/constants/forum';

export interface Handle {
	editorInstance: CKEditorInstance|null;
	getFileStore(): UploadedFile[];
	getImageStore(): UploadedImage[];
	getMediaStore(): UploadedMedia[];
}

interface Props {
	key: string;
	data: string;
	onChange: (data: string) => void;
	boardMeta?: BoardMeta|null;
}

const Editor = forwardRef<Handle, Props>(({ key = '', data = '', onChange, boardMeta }: Props, ref) =>
{
	const [ready, setReady] = useState<boolean>(false); // CKEditor가 준비되었는지 여부
	const [instanceLoaded, setInstanceLoaded] = useState<boolean>(false);
	const editorRef = useRef<typeof window.Editor|null>(null); // CKEditor 객체
	const editorInstanceRef = useRef<CKEditorInstance|null>(null);

	useEffect(() => {
		if (typeof window !== 'undefined' && window.Editor) {
			editorRef.current = window.Editor;
			setReady(true);
		}
	}, [key]); // 게시판 주소가 바뀌면 다시 ready 확인

	const handleScriptLoad = () => {
		if (typeof window !== 'undefined' && window.Editor) {
			editorRef.current = window.Editor;
			setReady(true);
		} else {
			console.error('CKEditor script not loaded properly.');
		}
	};

	// 외부에 접근 가능한 명령어
	useImperativeHandle(ref, () => ({
		editorInstance: editorInstanceRef.current,
		getFileStore: () => editorInstanceRef.current?._fileStore || [],
		getImageStore: () => editorInstanceRef.current?._imageStore || [],
		getMediaStore: () => editorInstanceRef.current?._mediaStore || []
	}), [instanceLoaded]);

	return (
		<>
			<Script src="/editor/editor.min.js" strategy="afterInteractive" onLoad={handleScriptLoad}/>

			{ready && editorRef.current ? (
				<CKEditor
					editor={editorRef.current}
					data={data}
					config={{
						placeholder: '내용을 입력하세요.',
						maxWordCount: PostConst.maxAllowedContentLength, // 최대 본문 길이

						// 이미지 설정
						allowImage: boardMeta?.write.allowImage ?? false,
						imageUploadLimit: boardMeta?.write.imageUploadLimit,
						imageUploadMaxSize: boardMeta?.write.imageUploadMaxSize,

						// 동영상 설정
						allowMedia: boardMeta?.write.allowMedia ?? false,
						mediaUploadLimit: boardMeta?.write.mediaUploadLimit,

						// 파일 설정
						allowFile: boardMeta?.write.allowFile ?? false,
						fileUploadLimit: boardMeta?.write.fileUploadLimit,
						fileUploadMaxSize: boardMeta?.write.fileUploadMaxSize,
						fileUploadExtension: boardMeta?.write.fileUploadExtension

						/*
						// 글자수 세기
						wordCount: {
							onUpdate: (stats: { characters: number; words: number }) => {
								document.getElementById('editorTxtLength')!.innerText = stats.characters.toString();
							}
						}
						*/
					}}
					onReady={(editor) => {
						console.log('Editor was initialized');

						// 최소 높이 설정
						editor.editing.view.change(writer => {
							const root = editor.editing.view.document.getRoot();
							if (root) {
								writer.setStyle('min-height', '300px', root);
							}
						});

						editorInstanceRef.current = editor;
						setInstanceLoaded(true);

						// 외부 내용을 복사 붙여넣기 가능하도록 처리
						editor.editing.view.document.on('paste', (_, data) => {
							const html = data.dataTransfer.getData('text/html');
							const text = data.dataTransfer.getData('text/plain');
							const content = (html || text);

							if (content) {
								const viewFragment = editor.data.processor.toView(content);
								const modelFragment = editor.data.toModel(viewFragment);

								editor.model.change(() => {
									editor.model.insertContent(modelFragment);
								});
							}
						});
					}}
					onChange={(_, editor) => {
						onChange?.(editor.getData());
					}}
				/>
			) : (
				<Loading/>
			)}
		</>
	);
});

// 컴포넌트 이름 지정
Editor.displayName = 'Editor';
export default Editor;