import { redirect, error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { exchangeAppleCode, decodeAppleIdToken } from '$lib/server/apple-auth';
import { env as publicEnv } from '$env/dynamic/public';
import * as auth from '$lib/server/auth';
import { db } from '$lib/server/db';
import { user as userTable } from '$lib/server/db/schema';
import { eq } from 'drizzle-orm';

export const POST: RequestHandler = async ({ request, cookies }) => {
	const formData = await request.formData();
	const code = formData.get('code')?.toString();
	const state = formData.get('state')?.toString();
	// Apple sends user info as JSON string on FIRST authorization only
	const userInfoStr = formData.get('user')?.toString();

	// Validate CSRF state
	const storedRaw = cookies.get('apple_oauth_state');
	if (!storedRaw || !state || !code) {
		throw error(400, 'Invalid OAuth callback');
	}
	const stored = JSON.parse(storedRaw) as { state: string; anonymousId: string };
	if (stored.state !== state) {
		throw error(400, 'State mismatch');
	}
	cookies.delete('apple_oauth_state', { path: '/' });

	const anonId = stored.anonymousId;
	if (!anonId) {
		console.error('[Apple auth] Missing anonymousId in state cookie');
		throw error(400, 'Missing anonymous ID — please return to the game and try again');
	}

	// Exchange authorization code for tokens
	const tokens = await exchangeAppleCode(code, `${publicEnv.PUBLIC_SITE_URL}/auth/apple/callback`);
	const claims = decodeAppleIdToken(tokens.id_token);
	const appleId = claims.sub;

	// Parse user info (only present on first authorization)
	let appleFirstName: string | undefined;
	let appleLastName: string | undefined;
	if (userInfoStr) {
		try {
			const userInfo = JSON.parse(userInfoStr);
			appleFirstName = userInfo.name?.firstName;
			appleLastName = userInfo.name?.lastName;
		} catch {
			/* ignore parse errors */
		}
	}

	// --- User resolution ---
	let userId: string;

	// 1. Check if a user with this appleId already exists (returning user)
	const existingAppleUser = await auth.getUserByAppleId(appleId);

	if (existingAppleUser) {
		userId = existingAppleUser.id;
		console.log(`[Apple auth] Returning Apple user: userId=${userId}, anonId=${anonId}`);
		await auth.migrateAnonymousStats(anonId, userId);
	} else if (claims.email) {
		// 2. Check if email matches an existing email/password user
		const existingEmailUser = await auth.getUserByEmail(claims.email);
		if (existingEmailUser) {
			// Link Apple account to existing user
			await db.update(userTable).set({ appleId }).where(eq(userTable.id, existingEmailUser.id));
			userId = existingEmailUser.id;
			console.log(`[Apple auth] Linked Apple to existing email user: userId=${userId}, anonId=${anonId}`);
			await auth.migrateAnonymousStats(anonId, userId);
		} else {
			// 3. Brand new user — use anonymousId as user ID to preserve local stats
			userId = anonId;
			console.log(`[Apple auth] New user (has email): userId=${userId}`);
			try {
				await db.insert(userTable).values({
					id: userId,
					email: claims.email,
					passwordHash: null,
					appleId,
					firstName: appleFirstName || null,
					lastName: appleLastName || null,
					isPrivate: false
				});
			} catch (e: any) {
				// Handle race condition: if appleId was inserted between our check and insert
				if (e?.message?.includes('UNIQUE constraint')) {
					const retryUser = await auth.getUserByAppleId(appleId);
					if (retryUser) {
						userId = retryUser.id;
						console.log(`[Apple auth] Race condition (has email): resolved to userId=${userId}, anonId=${anonId}`);
						await auth.migrateAnonymousStats(anonId, userId);
					} else {
						throw error(500, 'Failed to create user');
					}
				} else {
					throw e;
				}
			}
		}
	} else {
		// No email from Apple — create account with appleId only
		userId = anonId;
		console.log(`[Apple auth] New user (no email): userId=${userId}`);
		try {
			await db.insert(userTable).values({
				id: userId,
				email: null,
				passwordHash: null,
				appleId,
				firstName: appleFirstName || null,
				lastName: appleLastName || null,
				isPrivate: false
			});
		} catch (e: any) {
			if (e?.message?.includes('UNIQUE constraint')) {
				const retryUser = await auth.getUserByAppleId(appleId);
				if (retryUser) {
					userId = retryUser.id;
					console.log(`[Apple auth] Race condition (no email): resolved to userId=${userId}, anonId=${anonId}`);
					await auth.migrateAnonymousStats(anonId, userId);
				} else {
					throw error(500, 'Failed to create user');
				}
			} else {
				throw e;
			}
		}
	}

	// Create session
	const sessionToken = auth.generateSessionToken();
	const session = await auth.createSession(sessionToken, userId);
	auth.setSessionTokenCookie({ cookies }, sessionToken, session.expiresAt);

	redirect(302, '/');
};
