// Task Team — OAuth Routes (Google + Facebook + Apple) — 2026-03-29

async function oauthRoutes(app) {

    // OAuth config from environment
    const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID || '';
    const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET || '';
    const FACEBOOK_APP_ID = process.env.FACEBOOK_APP_ID || '';
    const FACEBOOK_APP_SECRET = process.env.FACEBOOK_APP_SECRET || '';
    const CALLBACK_BASE = process.env.OAUTH_CALLBACK_BASE || 'https://api.hasdo.info';

    // Helper: find or create user by OAuth provider
    async function findOrCreateOAuthUser(email, name, avatarUrl, provider, providerId) {
        if (!email) throw { statusCode: 400, message: `${provider} account has no email. Please use an account with email.` };

        // Check if user already exists by email
        let { rows } = await app.db.query('SELECT * FROM users WHERE email = $1', [email]);

        if (rows.length) {
            // Update provider info if not set
            const user = rows[0];
            if (!user.auth_provider_id || user.auth_provider !== provider) {
                await app.db.query(
                    'UPDATE users SET auth_provider = $1, auth_provider_id = $2, avatar_url = COALESCE(avatar_url, $3), updated_at = NOW() WHERE id = $4',
                    [provider, providerId, avatarUrl, user.id]
                );
            }
            return user;
        }

        // Create new user
        const insert = await app.db.query(
            'INSERT INTO users (email, name, avatar_url, auth_provider, auth_provider_id, language) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *',
            [email, name, avatarUrl, provider, providerId, 'cs']
        );
        return insert.rows[0];
    }

    // Helper: generate JWT and build response
    function buildAuthResponse(user) {
        const token = app.jwt.sign({ id: user.id, email: user.email }, { expiresIn: '7d' });
        return {
            data: {
                user: {
                    id: user.id,
                    email: user.email,
                    name: user.name,
                    avatar_url: user.avatar_url,
                    language: user.language
                },
                token
            }
        };
    }

    // ─── Google OAuth ─────────────────────────────────────────────

    // Google OAuth - initiate login flow
    app.get('/auth/google', async (req, reply) => {
        if (!GOOGLE_CLIENT_ID) {
            return { status: 'not_configured', message: 'Google OAuth not configured. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET env vars.' };
        }
        const params = new URLSearchParams({
            client_id: GOOGLE_CLIENT_ID,
            redirect_uri: `${CALLBACK_BASE}/api/v1/auth/google/callback`,
            response_type: 'code',
            scope: 'email profile',
            access_type: 'offline',
            prompt: 'select_account'
        });
        return reply.redirect(`https://accounts.google.com/o/oauth2/v2/auth?${params}`);
    });

    // Google OAuth - callback (exchange code for token)
    app.get('/auth/google/callback', async (req, reply) => {
        const { code, error } = req.query;
        if (error) throw { statusCode: 400, message: `Google auth error: ${error}` };
        if (!code) throw { statusCode: 400, message: 'No authorization code provided' };

        // Exchange authorization code for tokens
        const tokenRes = await fetch('https://oauth2.googleapis.com/token', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                code,
                client_id: GOOGLE_CLIENT_ID,
                client_secret: GOOGLE_CLIENT_SECRET,
                redirect_uri: `${CALLBACK_BASE}/api/v1/auth/google/callback`,
                grant_type: 'authorization_code'
            })
        });
        const tokens = await tokenRes.json();
        if (!tokens.access_token) {
            app.log.error({ tokens }, 'Google token exchange failed');
            throw { statusCode: 401, message: 'Google authentication failed' };
        }

        // Get user profile from Google
        const userRes = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
            headers: { Authorization: `Bearer ${tokens.access_token}` }
        });
        const gUser = await userRes.json();

        // Find or create user in our DB
        const user = await findOrCreateOAuthUser(
            gUser.email,
            gUser.name,
            gUser.picture,
            'google',
            gUser.id
        );

        const result = buildAuthResponse(user);

        // If there's a state param with redirect URL, redirect with token
        const redirectUrl = req.query.state;
        if (redirectUrl) {
            const sep = redirectUrl.includes('?') ? '&' : '?';
            return reply.redirect(`${redirectUrl}${sep}token=${result.data.token}`);
        }

        return result;
    });

    // Google OAuth - mobile/SPA token exchange (for clients that get the code directly)
    app.post('/auth/google/token', async (req) => {
        const { id_token, access_token } = req.body;
        if (!id_token && !access_token) throw { statusCode: 400, message: 'id_token or access_token required' };

        let gUser;
        if (access_token) {
            const userRes = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
                headers: { Authorization: `Bearer ${access_token}` }
            });
            gUser = await userRes.json();
        } else {
            // Verify id_token
            const verifyRes = await fetch(`https://oauth2.googleapis.com/tokeninfo?id_token=${id_token}`);
            gUser = await verifyRes.json();
            if (gUser.aud !== GOOGLE_CLIENT_ID) throw { statusCode: 401, message: 'Invalid token audience' };
        }

        if (!gUser.email) throw { statusCode: 401, message: 'Could not get email from Google' };

        const user = await findOrCreateOAuthUser(
            gUser.email,
            gUser.name || gUser.given_name,
            gUser.picture,
            'google',
            gUser.sub || gUser.id
        );

        return buildAuthResponse(user);
    });

    // ─── Facebook OAuth ───────────────────────────────────────────

    // Facebook OAuth - initiate login flow
    app.get('/auth/facebook', async (req, reply) => {
        if (!FACEBOOK_APP_ID) {
            return { status: 'not_configured', message: 'Facebook OAuth not configured. Set FACEBOOK_APP_ID and FACEBOOK_APP_SECRET env vars.' };
        }
        const params = new URLSearchParams({
            client_id: FACEBOOK_APP_ID,
            redirect_uri: `${CALLBACK_BASE}/api/v1/auth/facebook/callback`,
            scope: 'email,public_profile',
            response_type: 'code'
        });
        return reply.redirect(`https://www.facebook.com/v18.0/dialog/oauth?${params}`);
    });

    // Facebook OAuth - callback
    app.get('/auth/facebook/callback', async (req, reply) => {
        const { code, error, error_description } = req.query;
        if (error) throw { statusCode: 400, message: `Facebook auth error: ${error_description || error}` };
        if (!code) throw { statusCode: 400, message: 'No authorization code provided' };

        // Exchange code for access token
        const tokenParams = new URLSearchParams({
            client_id: FACEBOOK_APP_ID,
            redirect_uri: `${CALLBACK_BASE}/api/v1/auth/facebook/callback`,
            client_secret: FACEBOOK_APP_SECRET,
            code
        });
        const tokenRes = await fetch(`https://graph.facebook.com/v18.0/oauth/access_token?${tokenParams}`);
        const tokens = await tokenRes.json();
        if (!tokens.access_token) {
            app.log.error({ tokens }, 'Facebook token exchange failed');
            throw { statusCode: 401, message: 'Facebook authentication failed' };
        }

        // Get user profile from Facebook
        const userRes = await fetch(`https://graph.facebook.com/me?fields=id,name,email,picture.type(large)&access_token=${tokens.access_token}`);
        const fbUser = await userRes.json();

        const user = await findOrCreateOAuthUser(
            fbUser.email,
            fbUser.name,
            fbUser.picture?.data?.url,
            'facebook',
            fbUser.id
        );

        const result = buildAuthResponse(user);

        // Redirect if state was provided
        const redirectUrl = req.query.state;
        if (redirectUrl) {
            const sep = redirectUrl.includes('?') ? '&' : '?';
            return reply.redirect(`${redirectUrl}${sep}token=${result.data.token}`);
        }

        return result;
    });

    // Facebook OAuth - mobile/SPA token exchange
    app.post('/auth/facebook/token', async (req) => {
        const { access_token } = req.body;
        if (!access_token) throw { statusCode: 400, message: 'access_token required' };

        const userRes = await fetch(`https://graph.facebook.com/me?fields=id,name,email,picture.type(large)&access_token=${access_token}`);
        const fbUser = await userRes.json();
        if (fbUser.error) throw { statusCode: 401, message: fbUser.error.message };

        const user = await findOrCreateOAuthUser(
            fbUser.email,
            fbUser.name,
            fbUser.picture?.data?.url,
            'facebook',
            fbUser.id
        );

        return buildAuthResponse(user);
    });

    // ─── Apple Sign In ────────────────────────────────────────────

    // Apple Sign In - callback (Apple sends POST with id_token)
    app.post('/auth/apple/callback', async (req) => {
        // Apple sends: id_token, code, state, user (JSON string on first auth)
        const { id_token, user: userJson } = req.body;
        if (!id_token) throw { statusCode: 400, message: 'id_token required from Apple' };

        // Decode JWT payload (Apple id_token is a standard JWT)
        // In production, verify signature against Apple's public keys
        const parts = id_token.split('.');
        if (parts.length !== 3) throw { statusCode: 400, message: 'Invalid id_token format' };

        let payload;
        try {
            payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString());
        } catch (e) {
            throw { statusCode: 400, message: 'Could not decode id_token' };
        }

        const email = payload.email;
        if (!email) throw { statusCode: 400, message: 'No email in Apple id_token' };

        // Apple only sends user info on FIRST authorization
        let name = 'Apple User';
        if (userJson) {
            try {
                const appleUser = typeof userJson === 'string' ? JSON.parse(userJson) : userJson;
                if (appleUser.name) {
                    name = [appleUser.name.firstName, appleUser.name.lastName].filter(Boolean).join(' ');
                }
            } catch (e) { /* ignore parse errors */ }
        }

        const user = await findOrCreateOAuthUser(
            email,
            name,
            null,
            'apple',
            payload.sub
        );

        return buildAuthResponse(user);
    });

    // ─── OAuth Status ─────────────────────────────────────────────

    // Check which OAuth providers are configured
    app.get('/auth/providers', async () => {
        return {
            data: {
                email: true,
                google: !!GOOGLE_CLIENT_ID,
                facebook: !!FACEBOOK_APP_ID,
                apple: true  // Apple Sign In works with just client-side config
            }
        };
    });
}

module.exports = oauthRoutes;
