import { Router, Request, Response } from 'express';
import { PluginContext } from '../../../backend/src/core/types';
import { pluginConfig } from '../../../backend/src/core/plugin-config';
import { generateTokens } from '../../../backend/src/middleware/auth';

export function createGoogleOAuthRoutes(ctx: PluginContext): Router {
    const router = Router();
    const { db } = ctx;
    const storedConfig = pluginConfig.get('google-oauth') || {};
    const GOOGLE_CLIENT_ID = storedConfig.clientId || process.env.GOOGLE_CLIENT_ID;
    const GOOGLE_CLIENT_SECRET = storedConfig.clientSecret || process.env.GOOGLE_CLIENT_SECRET;
    const GOOGLE_CALLBACK = storedConfig.callbackUrl || process.env.GOOGLE_CALLBACK_URL || '/api/auth/google/callback';
    const rawBasePath = storedConfig.basePath || process.env.NEXT_PUBLIC_BASE_PATH || process.env.NEXT_BASE_PATH || '';
    const basePath = rawBasePath ? `/${String(rawBasePath).replace(/^\/+|\/+$/g, '')}` : '';

    // GET / — Redirect to Google
    router.get('/', (req: Request, res: Response) => {
        if (!GOOGLE_CLIENT_ID) return res.status(503).json({ error: 'Google OAuth não configurado' });

        const reqBasePath = req.query.basePath as string || '';
        const state = reqBasePath ? Buffer.from(JSON.stringify({ basePath: reqBasePath })).toString('base64') : '';

        // ALWAYS use the registered GOOGLE_CALLBACK URI for the OAuth flow
        // The 'state' parameter will carry the basePath information to route back correctly
        const redirectUri = GOOGLE_CALLBACK;

        const url = `https://accounts.google.com/o/oauth2/v2/auth?` +
            `client_id=${GOOGLE_CLIENT_ID}&redirect_uri=${encodeURIComponent(redirectUri)}` +
            `&response_type=code&scope=openid%20email%20profile&access_type=offline` +
            (state ? `&state=${encodeURIComponent(state)}` : '');

        res.redirect(url);
    });

    // GET /callback — Handle Google callback
    router.get('/callback', async (req: Request, res: Response) => {
        try {
            const { code } = req.query;
            if (!code || !GOOGLE_CLIENT_ID || !GOOGLE_CLIENT_SECRET) {
                return res.status(400).json({ error: 'Código ou config ausente' });
            }

            // Recover basePath from state
            const { state } = req.query;
            let currentBasePath = ''; // Default to root for Live
            const targetRedirectUri = GOOGLE_CALLBACK; // Standard URI used for the code exchange

            if (state) {
                try {
                    const decodedState = JSON.parse(Buffer.from(state as string, 'base64').toString());
                    if (decodedState.basePath) {
                        currentBasePath = decodedState.basePath;
                        // Always ensure basePath starts with / and doesn't end with /
                        currentBasePath = `/${String(currentBasePath).replace(/^\/+|\/+$/g, '')}`;
                        if (currentBasePath === '/') currentBasePath = '';
                    }
                } catch (e) {
                    ctx.logger.error(`Error decoding OAuth state: ${e}`);
                }
            }

            // Exchange code for token
            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: targetRedirectUri, grant_type: 'authorization_code',
                }),
            });
            const tokenData = await tokenRes.json() as any;
            if (!tokenRes.ok || !tokenData?.access_token) {
                ctx.logger.error(`Google OAuth token error: ${JSON.stringify(tokenData)}`);
                return res.status(400).json({ error: 'Falha ao obter token do Google' });
            }

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

            ctx.logger.info(`Google User Info: ${JSON.stringify(googleUser)}`);

            if (!userRes.ok || !googleUser?.email) {
                ctx.logger.error(`Google OAuth userinfo error: ${JSON.stringify(googleUser)}`);
                return res.status(400).json({ error: 'Falha ao obter e-mail do Google' });
            }

            // Find or create user
            let user = await db('users').where({ email: googleUser.email }).first();
            if (!user) {
                const [id] = await db('users').insert({
                    name: googleUser.name, email: googleUser.email,
                    role: 'user', status: 'active', google_id: googleUser.id,
                    created_at: new Date(),
                    updated_at: new Date(),
                });
                user = { id, name: googleUser.name, email: googleUser.email, role: 'user' };
            } else if (!user.google_id) {
                await db('users').where({ id: user.id }).update({ google_id: googleUser.id, updated_at: new Date() });
            }
            if (user.deleted_at || user.status === 'banned') {
                return res.status(401).json({ error: 'Conta desativada' });
            }

            const tokens = generateTokens(user);

            await ctx.hooks.emit('user:google_login', { userId: user.id, email: user.email });

            // Redirect to frontend with token
            res.redirect(`${currentBasePath}/login?token=${encodeURIComponent(tokens.accessToken)}&google=1`);
        } catch (err: any) {
            ctx.logger.error(`Google OAuth error: ${err.message}`);
            res.status(500).json({ error: 'Erro no OAuth' });
        }
    });

    return router;
}
