import { createHmac, randomBytes } from 'node:crypto';
import { env } from '$env/dynamic/private';

const OAUTH_STATE_COOKIE = 'google_oauth_state';
const OAUTH_STATE_MAX_AGE = 60 * 10; // 10 menit

export interface GoogleUserInfo {
	id: string;
	email: string;
	name: string;
	picture?: string;
	verified_email?: boolean;
}

function getSecret(): string {
	return env.SESSION_SECRET ?? 'catatan-warung-dev-secret-change-in-production';
}

function sign(value: string): string {
	return createHmac('sha256', getSecret()).update(value).digest('base64url');
}

export function isGoogleAuthEnabled(): boolean {
	return Boolean(env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET);
}

export function getGoogleRedirectUri(origin: string): string {
	return env.GOOGLE_REDIRECT_URI ?? `${origin}/auth/google/callback`;
}

export function createOAuthState(mode: 'login' | 'register'): string {
	const nonce = randomBytes(16).toString('base64url');
	const payload = `${mode}:${nonce}`;
	return `${payload}.${sign(payload)}`;
}

export function verifyOAuthState(state: string): 'login' | 'register' | null {
	const lastDot = state.lastIndexOf('.');
	if (lastDot === -1) return null;

	const payload = state.slice(0, lastDot);
	const signature = state.slice(lastDot + 1);
	if (!payload || sign(payload) !== signature) return null;

	const mode = payload.split(':')[0];
	if (mode === 'login' || mode === 'register') return mode;
	return null;
}

export function getOAuthStateCookieOptions() {
	return {
		path: '/',
		httpOnly: true,
		sameSite: 'lax' as const,
		secure: process.env.NODE_ENV === 'production',
		maxAge: OAUTH_STATE_MAX_AGE
	};
}

export function buildGoogleAuthUrl(
	origin: string,
	mode: 'login' | 'register'
): { url: string; state: string } {
	const clientId = env.GOOGLE_CLIENT_ID;
	if (!clientId) throw new Error('GOOGLE_CLIENT_ID tidak dikonfigurasi');

	const redirectUri = getGoogleRedirectUri(origin);
	const state = createOAuthState(mode);
	const params = new URLSearchParams({
		client_id: clientId,
		redirect_uri: redirectUri,
		response_type: 'code',
		scope: 'openid email profile',
		state,
		access_type: 'online',
		prompt: 'select_account'
	});

	return {
		url: `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`,
		state
	};
}

export async function exchangeGoogleCode(
	code: string,
	origin: string
): Promise<GoogleUserInfo> {
	const clientId = env.GOOGLE_CLIENT_ID;
	const clientSecret = env.GOOGLE_CLIENT_SECRET;
	if (!clientId || !clientSecret) {
		throw new Error('Google OAuth belum dikonfigurasi');
	}

	const redirectUri = getGoogleRedirectUri(origin);

	const tokenRes = await fetch('https://oauth2.googleapis.com/token', {
		method: 'POST',
		headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
		body: new URLSearchParams({
			code,
			client_id: clientId,
			client_secret: clientSecret,
			redirect_uri: redirectUri,
			grant_type: 'authorization_code'
		})
	});

	if (!tokenRes.ok) {
		throw new Error('Gagal menukar kode Google');
	}

	const tokenData = (await tokenRes.json()) as { access_token?: string };
	if (!tokenData.access_token) throw new Error('Token Google tidak valid');

	const userRes = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
		headers: { Authorization: `Bearer ${tokenData.access_token}` }
	});

	if (!userRes.ok) throw new Error('Gagal mengambil profil Google');

	const user = (await userRes.json()) as GoogleUserInfo;
	if (!user.id || !user.email) throw new Error('Data Google tidak lengkap');

	return user;
}

export { OAUTH_STATE_COOKIE };
