import { json, error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { db } from '$lib/server/db';
import { friendship, user } from '$lib/server/db/schema';
import { eq, and, or } from 'drizzle-orm';
import { encodeBase64url } from '@oslojs/encoding';
import { getLocalR2Url } from '$lib/server/r2';
import { notificationService } from '$lib/server/notifications';
import { pushService } from '$lib/server/push';

function generateFriendshipId(): string {
	const bytes = crypto.getRandomValues(new Uint8Array(15));
	return encodeBase64url(bytes);
}

export const GET: RequestHandler = async ({ url, locals }) => {
	if (!locals.user) {
		throw error(401, 'Unauthorized');
	}

	const status = url.searchParams.get('status') || 'accepted';
	const type = url.searchParams.get('type') || 'friends'; // 'friends', 'sent', 'received'

	try {
		let friendships;

		if (type === 'friends') {
			// Get accepted friendships where user is either sender or receiver
			const friendshipsRaw = await db
				.select({
					id: friendship.id,
					userId: friendship.userId,
					friendId: friendship.friendId,
					status: friendship.status,
					createdAt: friendship.createdAt
				})
				.from(friendship)
				.where(
					and(
						eq(friendship.status, status),
						or(eq(friendship.userId, locals.user.id), eq(friendship.friendId, locals.user.id))
					)
				);

			// Get friend details for each friendship
			friendships = await Promise.all(
				friendshipsRaw.map(async (f) => {
					const friendUserId = f.userId === locals.user!.id ? f.friendId : f.userId;
					const friendUser = await db
						.select({
							username: user.username,
							profilePictureUrl: user.profilePictureUrl
						})
						.from(user)
						.where(eq(user.id, friendUserId))
						.limit(1);

					return {
						id: f.id,
						userId: f.userId,
						friendId: f.friendId,
						status: f.status,
						createdAt: f.createdAt,
						friendUsername: friendUser[0]?.username || '',
						friendProfilePictureUrl: friendUser[0]?.profilePictureUrl || null
					};
				})
			);
		} else if (type === 'sent') {
			// Get friend requests sent by current user
			friendships = await db
				.select({
					id: friendship.id,
					userId: friendship.userId,
					friendId: friendship.friendId,
					status: friendship.status,
					createdAt: friendship.createdAt,
					friendUsername: user.username,
					friendProfilePictureUrl: user.profilePictureUrl
				})
				.from(friendship)
				.innerJoin(user, eq(friendship.friendId, user.id))
				.where(and(eq(friendship.userId, locals.user.id), eq(friendship.status, status)));
		} else if (type === 'received') {
			// Get friend requests received by current user
			friendships = await db
				.select({
					id: friendship.id,
					userId: friendship.userId,
					friendId: friendship.friendId,
					status: friendship.status,
					createdAt: friendship.createdAt,
					friendUsername: user.username,
					friendProfilePictureUrl: user.profilePictureUrl
				})
				.from(friendship)
				.innerJoin(user, eq(friendship.userId, user.id))
				.where(and(eq(friendship.friendId, locals.user.id), eq(friendship.status, status)));
		}

		// Generate local proxy URLs for profile pictures
		const friendshipsWithSignedUrls = (friendships || []).map((friendship) => {
			let profilePictureUrl = friendship.friendProfilePictureUrl;
			if (profilePictureUrl && !profilePictureUrl.startsWith('http')) {
				profilePictureUrl = getLocalR2Url(profilePictureUrl);
			}

			return {
				...friendship,
				friendProfilePictureUrl: profilePictureUrl
			};
		});

		return json(friendshipsWithSignedUrls);
	} catch (err) {
		console.error('Error loading friendships:', err);
		throw error(500, 'Failed to load friendships');
	}
};

export const POST: RequestHandler = async ({ request, locals }) => {
	if (!locals.user) {
		throw error(401, 'Unauthorized');
	}

	const data = await request.json();
	const { friendId } = data;

	if (!friendId) {
		throw error(400, 'Friend ID is required');
	}

	if (friendId === locals.user.id) {
		throw error(400, 'Cannot send friend request to yourself');
	}

	try {
		// Check if friend exists
		const friendExists = await db.select().from(user).where(eq(user.id, friendId)).limit(1);
		if (friendExists.length === 0) {
			throw error(404, 'User not found');
		}

		// Check if friendship already exists
		const existingFriendship = await db
			.select()
			.from(friendship)
			.where(
				or(
					and(eq(friendship.userId, locals.user.id), eq(friendship.friendId, friendId)),
					and(eq(friendship.userId, friendId), eq(friendship.friendId, locals.user.id))
				)
			)
			.limit(1);

		if (existingFriendship.length > 0) {
			const status = existingFriendship[0].status;
			if (status === 'accepted') {
				throw error(400, 'Already friends');
			} else if (status === 'pending') {
				throw error(400, 'Friend request already sent');
			} else if (status === 'blocked') {
				throw error(400, 'Cannot send friend request');
			}
		}

		// Create new friend request
		const newFriendship = await db
			.insert(friendship)
			.values({
				id: generateFriendshipId(),
				userId: locals.user.id,
				friendId,
				status: 'pending'
			})
			.returning();

		// Send notification to friend
		const shouldNotify = await notificationService.shouldNotify(friendId, 'friend_request');
		if (shouldNotify) {
			await notificationService.createNotification({
				userId: friendId,
				type: 'friend_request',
				title: 'New friend request',
				message: `${locals.user.username} sent you a friend request`,
				data: {
					friendshipId: newFriendship[0].id,
					senderId: locals.user.id,
					senderUsername: locals.user.username
				}
			});

			// Send push notification
			await pushService.sendPushNotification(friendId, {
				title: 'New friend request',
				message: `${locals.user.username} sent you a friend request`,
				url: '/friends',
				tag: 'friend_request',
				data: {
					friendshipId: newFriendship[0].id,
					senderId: locals.user.id
				}
			});
		}

		return json({ success: true, friendship: newFriendship[0] });
	} catch (err) {
		console.error('Error sending friend request:', err);
		if (err instanceof Error && 'status' in err) {
			throw err;
		}
		throw error(500, 'Failed to send friend request');
	}
};
