'use client';

import './style.scss';
import { usePathname, useSearchParams } from 'next/navigation';
import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { BoardSort, PostSearchType } from '@/constants/forum';
import { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { fetchApi } from '@/lib/utils/client';
import useErrorAlert from '@/hooks/useErrorAlert';
import Loading from '@/app/component/Loading';
import Pagination from '@/app/component/Pagination';
import { BoardPostsResponse } from '@/types/response/forum/board';
import Post from '@/types/forum/post';
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import LatestListLayout from './_component/LatestListLayout';

type ViewProps = {
	_query: {
		page: number;
		perPage: number;
		sort?: BoardSort;
		search: PostSearchType;
		keyword?: string;
	},
	_postList: BoardPostsResponse
};

export default function View({ _query, _postList }: ViewProps)
{
	const pathname = usePathname();
	const searchParams = useSearchParams();
	const { setError } = useErrorAlert();
	const [loading, setLoading] = useState<boolean>(false);
	const [total, setTotal] = useState<number>(_postList.total);
	const [list, setList] = useState<Post[]>(_postList.list);
	const [page, setPage] = useState<number>(_query.page);
	const [perPage, setPerPage] = useState<number>(_query.perPage);
	const [sort, setSort] = useState<BoardSort|undefined>(_query.sort);
	const [search, setSearch] = useState<PostSearchType>(_query.search);
	const [keyword, setKeyword] = useState<string|undefined>(_query.keyword);
	const [params, setParams] = useState<Record<string, string>>({});
	const [searchDialogOpen, setSearchDialogOpen] = useState(false);
	const isMounted = useRef(false);
	const searchRef = useRef(search);
	const keywordRef = useRef(keyword);
	searchRef.current = search;
	keywordRef.current = keyword;
	const startIndex = useMemo(() => total - ((page - 1) * perPage), [total, page, perPage]);

	// 상태 => URL 동기화
	useEffect(() => {
		const alreadyParams = new URLSearchParams(searchParams.toString());

		Object.entries(params).forEach(([k, v]) => {
			if (v) {
				alreadyParams.set(k, v);
			} else {
				alreadyParams.delete(k);
			}
		});

		const queryString = `?${alreadyParams.toString()}`;
		if (window.location.search !== queryString) {
			window.history.replaceState(null, '', `${pathname}${queryString}`);
		}

	}, [page, perPage, sort, search, keyword, params, pathname, searchParams]);

	const handleFetchPosts = useCallback(async () => {
		try {
			setLoading(true);

			const queryParams = new URLSearchParams();

			queryParams.set('page', String(page));
			queryParams.set('perPage', String(perPage));

			if (sort !== undefined && sort !== null) {
				queryParams.set('sort', String(sort));
			}
			if (searchRef.current !== undefined && searchRef.current !== null) {
				queryParams.set('search', String(searchRef.current));
			}
			if (keywordRef.current) {
				queryParams.set('keyword', keywordRef.current);
			}

			const res = await fetchApi<BoardPostsResponse>(`/api/forum/posts?${queryParams.toString()}`);

			if (!res.data) {
				setError('게시글을 불러올 수 없습니다.');
			} else {
				setTotal(res.data.total);
				setList(res.data.list);
			}
		} catch (err) {
			if (err instanceof Error) {
				setError(err.message || '알 수 없는 오류가 발생했습니다.');
			}
		} finally {
			setLoading(false);
		}
	}, [page, perPage, sort]);

	const handlePageChange = useCallback((page: number) => {
		setPage(page);
		setParams((prev) => ({ ...prev, page: String(page) }));
	}, []);

	const handleChange = useCallback((e: React.ChangeEvent<HTMLSelectElement|HTMLInputElement>) => {
		const { name, value } = e.target;

		switch (name) {
			case 'sort':
				setSort(Number(value) as BoardSort);
				break;
			case 'perPage':
				setPerPage(Number(value));
				break;
			case 'search':
				setSearch(Number(value) as PostSearchType);
				break;
			case 'keyword':
				setKeyword(value);
				break;
		}

		if (['perPage', 'search', 'keyword'].includes(name)) {
			handlePageChange(1);
		}

		setParams((prev) => ({ ...prev, [name]: value }));
	}, [handlePageChange]);

	const handleSearch = useCallback((e: React.FormEvent) => {
		e.preventDefault();
		handleFetchPosts();
	}, [handleFetchPosts]);

	const handleSearchDialog = useCallback((e: React.FormEvent) => {
		e.preventDefault();
		handleFetchPosts();
		setSearchDialogOpen(false);
	}, [handleFetchPosts]);

	useEffect(() => {
		if (!isMounted.current) {
			isMounted.current = true;
			return;
		}

		handleFetchPosts();
	}, [page, perPage, sort, handleFetchPosts]);

	return (
		<div id='latest'>
			{loading && <Loading />}

			<div className='list-header'>
				<section>
					<h1>토론</h1>
				</section>

				{/* 정렬 */}
				<section aria-label='게시글 정렬'>
					<select name='sort' value={sort ?? ''} title='게시글 정렬' onChange={handleChange}>
						<option value={BoardSort.CreatedAt}>최신순</option>
						<option value={BoardSort.Views}>조회순</option>
						<option value={BoardSort.Comments}>댓글순</option>
						<option value={BoardSort.Likes}>공감순</option>
					</select>
				</section>

				{/* 출력 수 */}
				<section aria-label='게시글 출력 수'>
					<select name='perPage' value={perPage} title='출력 수' onChange={handleChange}>
						<option value='10'>10개씩</option>
						<option value='20'>20개씩</option>
						<option value='30'>30개씩</option>
						<option value='50'>50개씩</option>
						<option value='100'>100개씩</option>
					</select>
				</section>
			</div>

			{/* 게시글 목록 */}
			<LatestListLayout list={list} startIndex={startIndex} />

			{/* 검색 */}
			<div className='list-footer'>
				{/* 모바일: 검색 아이콘 → Dialog */}
				<Dialog open={searchDialogOpen} onOpenChange={setSearchDialogOpen}>
					<DialogTrigger asChild>
						<button type='button' className='btn btn-default search-toggle' title='검색'>
							<FontAwesomeIcon icon={faMagnifyingGlass}/>
						</button>
					</DialogTrigger>
					<DialogContent className='w-[90%] sm:max-w-md'>
						<DialogHeader>
							<DialogTitle>게시글 검색</DialogTitle>
						</DialogHeader>
						<form onSubmit={handleSearchDialog} autoComplete='off' className='flex flex-col gap-3'>
							<select name='search' value={search ?? ''} title='검색 구분' onChange={handleChange} className='h-9 rounded-md border px-3'>
								<option value={PostSearchType.Subject}>제목</option>
								<option value={PostSearchType.Content}>내용</option>
								<option value={PostSearchType.Author}>작성자</option>
								<option value={PostSearchType.Comment}>댓글</option>
							</select>
							<input type='text' name='keyword' value={keyword} placeholder='검색어를 입력해주세요.' onChange={handleChange} className='h-9 rounded-md border px-3' />
							<button type='submit' className='btn btn-default w-full'>검색</button>
						</form>
					</DialogContent>
				</Dialog>

				{/* 데스크톱: 인라인 검색 폼 */}
				<section aria-label='게시글 검색'>
					<form onSubmit={handleSearch} autoComplete='off'>
						<select name='search' value={search ?? ''} title='검색 구분' onChange={handleChange}>
							<option value={PostSearchType.Subject}>제목</option>
							<option value={PostSearchType.Content}>내용</option>
							<option value={PostSearchType.Author}>작성자</option>
							<option value={PostSearchType.Comment}>댓글</option>
						</select>
						<input type='text' name='keyword' value={keyword} placeholder='검색어를 입력해주세요.' onChange={handleChange} />
						<button type='submit' className='btn btn-default'>검색</button>
					</form>
				</section>
			</div>

			<Pagination total={total} page={page} perPage={perPage} onChange={handlePageChange} />
		</div>
	);
}