'use client';

import './style.scss';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
import { useState, useEffect, useCallback, useRef, FormEvent } from 'react';
import Loading from '@/app/component/Loading';
import { BoardLayout, PostConst } from '@/constants/forum';
import { fetchBoard, fetchBoardList } from '@/lib/api/forum/board';
import { fetchPostCreate } from '@/lib/api/forum/post';
import { throwError } from '@/lib/utils/client';
import boardResponse from '@/dtos/response/forum/board/boardResponse';
import BoardListResponse from '@/dtos/response/forum/board/boardListResponse';
import Editor, { Handle } from '../_component/Editor';
import HeaderContent from '../_component/HeaderContent';
import FooterContent from '../_component/FooterContent';
import PostTagInput from '../_component/PostTagInput';

export default function View()
{
	const router = useRouter();
	const editorRef = useRef<Handle>(null);
	const [error, setError] = useState<string|null>(null);
	const [loading, setLoading] = useState<boolean>(false);
	const [isChanged, setIsChanged] = useState<boolean>(false);
	const [board, setBoard] = useState<boardResponse|null>(null);
	const [boardList, setBoardList] = useState<BoardListResponse[]>([]);
	const [boardCode, setBoardCode] = useState<string>('');
	const [boardPrefix, setBoardPrefix] = useState<string>('');
	const [subject, setSubject] = useState<string>('');
	const [content, setContent] = useState<string>('');
	const [isSecret, setIsSecret] = useState<boolean>(false);
	const [isNotice, setIsNotice] = useState<boolean>(false);
	const [isSpeaker, setIsSpeaker] = useState<boolean>(false);
	const [tags, setTags] = useState<string[]>([]);

	const boardCodeRef = useRef<HTMLSelectElement>(null);
	const boardPrefixRef = useRef<HTMLSelectElement>(null);
	const subjectRef = useRef<HTMLInputElement>(null);
	const contentRef = useRef<HTMLTextAreaElement>(null);

	useEffect(() => {
		if (error) {
			alert(error);
			setError(null);
		}
	}, [error]);

	useEffect(() => {
		const hash = window.location.hash;
		if (hash) {
			setBoardCode(hash.substring(1));
		}
	}, []);

	useEffect(() => {
		if (boardCode) {
			setLoading(true);

			// 게시판 상세 정보 호출
			fetchBoard(boardCode).then((res) => {
				if (res.success) {
					setBoard(res.data);
				} else {
					throw new Error('게시판을 조회할 수 없습니다.');
				}
			}).catch((err) => {
				setError(err.message);
			}).finally(() => {
				setLoading(false);
			});
		}
	}, [boardCode]);

	// 게시판 변경 시
	useEffect(() => {
		if (board) {
			resetForm();

			// 게시판 목록 호출
			if (boardList.length <= 0) {
				fetchBoardList(board.boardGroup.code).then((res) => {
					if (res.success) {
						if (res.data && res.data.length >= 0) {
							setBoardList(res.data);
						}
					} else {
						throw new Error('게시판을 조회할 수 없습니다.');
					}
				}).catch((err) => {
					setError(err.message);
				}).finally(() => {
					setLoading(false);
				});
			}
		}
	}, [board]);

	// 게시글 초기화
	const resetForm = () => {
		setError('');
		setIsChanged(false);
		setBoardPrefix('');
		setSubject(board?.boardMeta.write.defaultSubject || '');
		setContent(board?.boardMeta.write.defaultContent || '');
		setIsSecret(false);
		setIsNotice(false);
		setIsSpeaker(false);
		setTags([]);

		// Editor 초기화
		if (editorRef.current?.editorInstance) {
			editorRef.current.editorInstance.setData(content);
		}
	};

	// 게시판 선택 시
	const handleBoardChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
		const code = e.target.value;

		if (isChanged) {
			if (!confirm('작성 중인 내용이 사라질 수 있습니다. 게시판을 변경하시겠습니까?')) {
				return
			}
		}

		setBoardCode(code);
		setIsChanged(false);
	};

	// 제목, 내용, 말머리 변경 시
	const handleChange = (e: React.ChangeEvent<HTMLSelectElement|HTMLInputElement|HTMLTextAreaElement>) => {
		const { name, value } = e.target as HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement;
		const checked = (e.target as HTMLInputElement).checked;

		switch (name) {
			case 'boardPrefix':
				setBoardPrefix(value);
				break;
			case 'isSecret':
				setIsSecret(checked);
				break;
			case 'isNotice':
				setIsNotice(checked);
				setIsSpeaker(false);
				break;
			case 'isSpeaker':
				setIsSpeaker(checked);
				setIsNotice(false);
				break;
			case 'subject':
				setSubject(value);
				break;
			case 'content':
				setContent(value);
				break;
		}

		setIsChanged(true);
	};

	// CKEditor에서 내용 변경 시
	const handleEditorChange = useCallback((data: string) => {
		setContent(data);
		setIsChanged(true);
	}, []);

	const validate = () => {
		if (!boardCode || !board) {
			boardCodeRef.current!.focus();
			throw new Error('게시판을 선택해주세요.');
		}

		if (board.boardMeta.write.allowPrefix && board.boardMeta.write.requiredPrefix && !boardPrefix) {
			boardPrefixRef.current!.focus();
			throw new Error((board.boardMeta.list.layout === BoardLayout.QnA ? '분류' : '말머리') + '를 선택해주세요.');
		}

		if (!subject) {
			subjectRef.current!.focus();
			throw new Error('제목을 입력해주세요.');
		} else if (subject.length > PostConst.MaxAllowedSubjectLength) {
			subjectRef.current!.focus();
			throw new Error(`제목은 ${PostConst.MaxAllowedSubjectLength}자 이내로 작성해주세요.`);
		}

		if (!content) {
			if (board.boardMeta.write.allowEditor) {
				editorRef.current!.editorInstance?.editing.view.focus();
			} else {
				contentRef.current!.focus();
			}

			throw new Error('내용을 입력해주세요.');
		} else if (!board.boardMeta.write.allowEditor) {
			// 기본 textarea 사용 시 글자 수 검사
			if (content.length > PostConst.MaxAllowedContentLength) {
				contentRef.current!.focus();
				throw new Error(`내용은 ${PostConst.MaxAllowedContentLength}자 이내로 작성해주세요.`);
			}
		}

		if (board.boardMeta.write.allowTag && tags.length > board.boardMeta.write.tagLimit) {
			throw new Error(`태그는 ${board.boardMeta.write.tagLimit}개 이내로 작성해주세요.`);
		}
	};

	// 게시글 등록 처리
	const handleSubmit = useCallback(async (e: FormEvent) => {
		e.preventDefault();

		try {

			validate();
			setLoading(true);

			if (!board) {
				throw new Error('게시판을 선택해 주세요.');
			}

			const formData = new FormData();
			formData.append('boardID', String(board.id));
			formData.append('boardCode', boardCode);
			formData.append('boardPrefixID', boardPrefix);
			formData.append('isSecret', String(isSecret));
			formData.append('isNotice', String(isNotice));
			formData.append('isSpeaker', String(isSpeaker));
			formData.append('subject', subject);

			if (content) {
				const doc = new DOMParser().parseFromString(content, 'text/html');
				doc.querySelectorAll('img[src]').forEach(img => {
					img.setAttribute('src', 'data:image/');
				});

				formData.append('content', doc.body.innerHTML);
			}

			// 태그
			if (board.boardMeta.write.allowTag) {
				tags.forEach(tag => formData.append('tags', tag));
			}

			// 이미지 정보
			if (board.boardMeta.write.allowEditor && board.boardMeta.write.allowImage) {
				editorRef.current?.getImageStore().forEach(i => {
					if (i.image?.size > 0 && i.name) {
						formData.append('images', i.image, i.name);
					}
				});
			}

			// 미디어 정보
			if (board.boardMeta.write.allowEditor && board.boardMeta.write.allowMedia) {
				editorRef.current!.getMediaStore().forEach((m) => {
					if (m.url) {
						formData.append('medias', m.url);
					}
				});
			}

			// 첨부 파일
			if (board.boardMeta.write.allowEditor && board.boardMeta.write.allowFile) {
				editorRef.current!.getFileStore().forEach(f => {
					if (f?.size > 0 && f.name) {
						formData.append('files', f.file, f.name);
					}
				});
			}

			const res = await fetchPostCreate(formData);

			if (res.success) {
				resetForm();
				router.push(`/post/${res.data!.id}`);
			} else {
				throwError(res);
			}

		} catch (err: any) {
			setError(err.message);
		} finally {
			setLoading(false);
		}
	}, [boardCode, board, boardPrefix, subject, content, isSecret, isNotice, isSpeaker, tags]);

	return (
		<form id='postWrite' onSubmit={handleSubmit}>
			{loading && <Loading />}

			<fieldset>
				<legend><h1>{board?.name} 글쓰기</h1></legend>

				{/* 상단 안내 */}
				{<HeaderContent isEnabled={board?.boardMeta.write.showHeader} content={board?.boardMeta.write.headerContent}/>}

				{/* 게시판 선택, 말머리, 비밀글, 공지, 전체 공지 */}
				<section>

					{/* 게시판 선택 */}
					<article>
						<select name='boardCode' ref={boardCodeRef} value={boardCode} onChange={handleBoardChange} title='게시판 선택'>
							<option value=''>게시판 선택</option>
							{boardList.map((board) => (
								<option key={board.code} value={board.code}>{board.name}</option>
							))}
						</select>
					</article>

					{/* 말머리 */}
					{board?.boardMeta.write.allowPrefix && (
						<article>
							<select name='boardPrefix' ref={boardPrefixRef} value={boardPrefix} onChange={handleChange} title='말머리 선택'>
								<option value=''>{(board.boardMeta.list.layout === BoardLayout.QnA ? '분류' : '말머리') + ' 선택'}</option>
								{board?.boardPrefix.map((row) => (
									<option key={row.id} value={row.id}>{row.name}</option>
								))}
							</select>
						</article>
					)}

					<article>
						{/* 비밀글 */}
						{board?.boardMeta.write.allowSecret && (
							<>
								<input type='checkbox' name='isSecret' id='isSecret' checked={isSecret} onChange={handleChange} />
								<label htmlFor='isSecret'>비밀글</label>
							</>
						)}

						{/* 해당 게시판 공지 */}
						<input type='checkbox' name='isNotice' id='isNotice' checked={isNotice} onChange={handleChange} />
						<label htmlFor='isNotice'>공지</label>

						{/* 게시판 전체 공지 */}
						<input type='checkbox' name='isSpeaker' id='isSpeaker' checked={isSpeaker} onChange={handleChange} />
						<label htmlFor='isSpeaker'>전체 공지</label>
					</article>
				</section>

				{/* 제목 */}
				<section>
					<input type='text' name='subject' ref={subjectRef} value={subject} onChange={handleChange} placeholder='글 제목을 입력해주세요.' autoFocus maxLength={PostConst.MaxAllowedSubjectLength} />
				</section>

				{/* 내용 */}
				<section>
					{board?.boardMeta.write.allowEditor ?
					(
						<Editor ref={editorRef} key={boardCode} data={content} onChange={handleEditorChange} boardMeta={board?.boardMeta} />
					) : (
						<textarea name='content' ref={contentRef} value={content} onChange={handleChange} placeholder='내용을 입력해주세요.' maxLength={PostConst.MaxAllowedContentLength}></textarea>
					)}
				</section>

				{/* 태그 */}
				{board?.boardMeta.write?.allowTag && (
					<section id='postTag'>
						<PostTagInput value={tags} onChange={setTags} maxTags={board.boardMeta.write.tagLimit} />
					</section>
				)}

				{/* 하단 안내 */}
				{<FooterContent isEnabled={board?.boardMeta.write.showFooter} content={board?.boardMeta.write.footerContent}/>}

				<br/>

				<section>
					<button type='submit' className='btn btn-submit' disabled={loading}>
						{ loading ? '등록 중…' : '확인' }
					</button>
					<Link href={`/board/${boardCode || 'latest'}`} className='btn btn-default'>취소</Link>
				</section>
			</fieldset>
		</form>
	);
}