'use client';

import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import type { ChannelSearchRow, ProductType } from '@/types/store';

const STORAGE_KEY = 'dpot.cart.v1';
const MAX_QUANTITY_PER_LINE = 999;

export interface CartItem {
	productID: number;
	name: string;
	thumbnail: string|null;
	price: number;
	type: ProductType;
	gameName: string;
	stock: number;  // 스냅샷 — 결제 시 서버가 최종 검증. -1 = 무제한
	requireDonationChannel: boolean;  // 구매 시 후원 채널 필수 여부 (서버가 최종 강제)
	quantity: number;
}

type AddItemArgs = Omit<CartItem, 'quantity'> & { quantity: number };

export interface CartState {
	items: CartItem[];
	channel: ChannelSearchRow|null;
}

export interface CartContextValue extends CartState {
	addItem: (args: AddItemArgs) => void;
	updateQuantity: (productID: number, quantity: number) => void;
	removeItem: (productID: number) => void;
	setChannel: (channel: ChannelSearchRow|null) => void;
	clear: () => void;
	totalCount: number;
	totalPrice: number;
}

const CartContext = createContext<CartContextValue|null>(null);

function clampQty(value: number, stock: number): number
{
	const hardMax = stock > 0 ? Math.min(stock, MAX_QUANTITY_PER_LINE) : MAX_QUANTITY_PER_LINE;
	return Math.max(1, Math.min(value, hardMax));
}

function loadFromStorage(): CartState
{
	if (typeof window === 'undefined') {
		return { items: [], channel: null };
	}

	try {
		const raw = window.localStorage.getItem(STORAGE_KEY);

		if (!raw) {
			return { items: [], channel: null };
		}

		const parsed = JSON.parse(raw) as CartState;

		if (!parsed || !Array.isArray(parsed.items)) {
			return { items: [], channel: null };
		}

		return {
			items: parsed.items
				.filter(i => i && typeof i.productID === 'number' && typeof i.quantity === 'number')
				.map(i => ({ ...i, requireDonationChannel: Boolean(i.requireDonationChannel) })),
			channel: parsed.channel ?? null
		};
	}
	catch {
		return { items: [], channel: null };
	}
}

export function CartProvider({ children }: { children: React.ReactNode })
{
	const [state, setState] = useState<CartState>({ items: [], channel: null });
	const [hydrated, setHydrated] = useState(false);

	// SSR 안전 hydration
	useEffect(() => {
		setState(loadFromStorage());
		setHydrated(true);
	}, []);

	// state 변경 시 localStorage 영구화 (hydration 후만)
	useEffect(() => {
		if (!hydrated) {
			return;
		}

		try {
			window.localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
		}
		catch {
			// quota 초과 등 — 무시
		}
	}, [state, hydrated]);

	const addItem = useCallback((args: AddItemArgs) => {
		setState(prev => {
			const existing = prev.items.find(i => i.productID === args.productID);

			if (existing) {
				const merged = clampQty(existing.quantity + args.quantity, args.stock);

				return {
					...prev,
					items: prev.items.map(i =>
						i.productID === args.productID
							? { ...i, quantity: merged, price: args.price, stock: args.stock, thumbnail: args.thumbnail, name: args.name, type: args.type, gameName: args.gameName, requireDonationChannel: args.requireDonationChannel }
							: i
					)
				};
			}

			return {
				...prev,
				items: [...prev.items, { ...args, quantity: clampQty(args.quantity, args.stock) }]
			};
		});
	}, []);

	const updateQuantity = useCallback((productID: number, quantity: number) => {
		setState(prev => ({
			...prev,
			items: prev.items.map(i =>
				i.productID === productID
					? { ...i, quantity: clampQty(quantity, i.stock) }
					: i
			)
		}));
	}, []);

	const removeItem = useCallback((productID: number) => {
		setState(prev => ({
			...prev,
			items: prev.items.filter(i => i.productID !== productID)
		}));
	}, []);

	const setChannel = useCallback((channel: ChannelSearchRow|null) => {
		setState(prev => ({ ...prev, channel }));
	}, []);

	const clear = useCallback(() => {
		setState({ items: [], channel: null });
	}, []);

	const totalCount = useMemo(
		() => state.items.reduce((sum, i) => sum + i.quantity, 0),
		[state.items]
	);

	const totalPrice = useMemo(
		() => state.items.reduce((sum, i) => sum + i.price * i.quantity, 0),
		[state.items]
	);

	const value: CartContextValue = useMemo(() => ({
		items: state.items,
		channel: state.channel,
		addItem,
		updateQuantity,
		removeItem,
		setChannel,
		clear,
		totalCount,
		totalPrice
	}), [state.items, state.channel, addItem, updateQuantity, removeItem, setChannel, clear, totalCount, totalPrice]);

	return (
		<CartContext.Provider value={value}>
			{children}
		</CartContext.Provider>
	);
}

export function useCartContext(): CartContextValue
{
	const ctx = useContext(CartContext);

	if (ctx === null) {
		throw new Error('useCartContext는 CartProvider 내부에서만 사용 가능합니다.');
	}

	return ctx;
}
