'use server';

import { cookies } from 'next/headers'
import { ResultDto, TokenData, ApiError } from '@/types/response/common';
import BoardManager from '@/types/forum/boardManager';
import { MemberResponse } from '@/types/response/account/member';
import { CLAIM_NAME_IDENTIFIER, CLAIM_EMAIL, CLAIM_NAME } from '@/constants/common';

const API_URL = process.env.API_URL;

export async function fetchJson<T>(url: string, options: RequestInit = {}): Promise<ResultDto<T>> {
	try {

		const actionURL = `${API_URL}${url.startsWith('/') ? url : `/${url}`}`;
		const cookie = await cookies();
		const cookieData = cookie.getAll().filter(c => c.name !== 'member').map(c => `${c.name}=${c.value}`).join("; ");
		const accessToken = cookie.get('accessToken')?.value;

		const res = await fetch(actionURL, {
			...options,
			headers: {
				...(options.body && !(options.body instanceof FormData) ? { 'Content-Type': 'application/json' } : {}),
				...(options.headers || {}),
				...(accessToken ? { 'Authorization': `Bearer ${accessToken}` } : {}),
				Cookie: cookieData,
				'Accept': 'application/json'
			},
			cache: 'no-store'
		});

		// Set-Cookie 헤더 처리 — 백엔드 응답 쿠키를 Next.js 쿠키 저장소에 저장
		const setCookieHeader = res.headers.getSetCookie();
		if (setCookieHeader && setCookieHeader.length > 0)
		{
			const cookieStore = await cookies();
			for (const cookieString of setCookieHeader) {
				const parts = cookieString.split(';').map(p => p.trim());
				const [nameValue, ...attributes] = parts;
				const eqIndex = nameValue.indexOf('=');

				if (eqIndex === -1) {
					continue;
				}

				const name = nameValue.substring(0, eqIndex);
				const value = nameValue.substring(eqIndex + 1);
				const options: Record<string, unknown> = {};

				for (const attr of attributes) {
					const [key, val] = attr.split('=');
					const lowerKey = key.toLowerCase().trim();
					if (lowerKey === 'httponly') options.httpOnly = true;
					else if (lowerKey === 'secure') options.secure = true;
					else if (lowerKey === 'path') options.path = val;
					else if (lowerKey === 'samesite') options.sameSite = val?.toLowerCase() as 'lax' | 'strict' | 'none';
					else if (lowerKey === 'max-age') options.maxAge = parseInt(val);
					else if (lowerKey === 'expires') options.expires = new Date(val);
				}

				cookieStore.set(name, value, options);
			}
		}

		if (res.status === 204) {
			return { success: true, status: 204, message: null, data: null, errors: null } satisfies ResultDto<T>;
		}

		const contentType = res.headers.get('content-type');
		if (!contentType || !contentType.includes('application/json')) {
			return {
				success: false,
				status: res.status,
				message: null,
				data: null,
				errors: null
			} satisfies ResultDto<T>;
		}

		return await res.json() as ResultDto<T>;

	} catch (err) {
		let message = '서버와 통신이 불가합니다.';
		const status = 500;

		if (err instanceof Error) {
			message = err.message;
		}

		console.warn(`[${status}] ${message}`);

		return {
			success: false,
			status: status,
			message: message,
			data: null,
			errors: null
		} satisfies ResultDto<T>;
	}
}

export async function getAccessToken(): Promise<string|null> {
	return (await cookies()).get('accessToken')?.value ?? null;
}

export async function getRefreshToken(): Promise<string|null> {
	return (await cookies()).get('refreshToken')?.value ?? null;
}

// API 서버 URL 조회
export async function getAPIUrl(): Promise<string> {
	return process.env.API_URL as string;
}

// SignalR Crypto 서버 URL 조회
export async function getSignalRCryptoUrl(): Promise<string> {
	return process.env.SIGNALR_CRYPTO_URL as string;
}

// SignalR Chat 서버 URL 조회
export async function getSignalRChatUrl(): Promise<string> {
	return process.env.SIGNALR_CHAT_URL as string;
}

// JWT 토큰에서 사용자 정보 추출
export async function getTokenData(): Promise<TokenData|null> {
	try {

		const token = await getAccessToken();
		if (!token) {
			throw new Error('Access token not found');
		}

		const base64URL = token.split('.')[1]; // JWT의 Payload 부분
		const base64 = base64URL.replace(/-/g, '+').replace(/_/g, '/'); // Base64 형식 변환
		const jsonPayload = decodeURIComponent(
			atob(base64).split('').map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join('')
		);

		const payload = JSON.parse(jsonPayload);

		return {
			id: payload[CLAIM_NAME_IDENTIFIER] || null,
			email: payload[CLAIM_EMAIL] || null,
			name: payload[CLAIM_NAME] || null
		};

	} catch {
		return null;
	}
}

// 첫번째 오류 조회
export async function getFirstError(errors: ApiError[] | null): Promise<string|null> {
    if (!errors || errors.length === 0) {
        return null;
    }
    return errors[0].description ?? null;
}

// 서버 응답 메시지 분석
export async function throwError<T>(res: ResultDto<T>): Promise<void> {
	if (res.success) {
		return;
	}

	let message:string|null = await getFirstError(res.errors);

	if (!message && res.message) {
		message = res.message;
	}

	switch (res.status) {
		case 400:
			throw Error(message || '잘못된 요청입니다.');
		case 401:
			throw Error('로그인 후 이용해 주세요.');
		case 403:
			throw Error('권한이 없습니다.');
		case 404:
			throw Error('요청하신 페이지를 찾을 수 없습니다.');
	}

	if (message) {
		throw Error(message);
	}
}

// 게시판, 게시글, 댓글 등 권한 확인
export async function checkPermission(permission: number, boardManager: BoardManager[]): Promise<boolean> {
	if (permission <= -1) {
		return true;
	}

	const raw = (await cookies()).get('member')?.value;
	const member = raw ? JSON.parse(decodeURIComponent(raw)) as MemberResponse : null;

	if (!member) {
		return false;
	}

	// 최고관리자는 항상 허용
	if (member.isAdmin) {
		return true;
	}

	// 유효 권한 레벨 계산 (매니저=99, 일반=memberGrade.order)
	const isBoardManager = boardManager.some(manager => member.id && manager.user.email === member.email);
	const level = isBoardManager ? 99 : (member.memberGrade?.order ?? 0);

	return permission <= level;
}