import { Request, Response, NextFunction } from 'express';
import User, { IUser } from '../models/User.js';
import OrganizationMember, { OrgRole } from '../models/OrganizationMember.js';
import Organization from '../models/Organization.js';

// Extended user info with organization context
export interface IAppUser extends IUser {
    organizationId?: string;
    organizationRole?: OrgRole;
    organizationBanned?: boolean;
}

// Module augmentation for Express Request
declare module 'express-serve-static-core' {
    interface Request {
        appUser?: IAppUser;
    }
}

/**
 * Middleware to extract and verify user from Auth ID header
 * Also loads organization-specific role if organization context is provided
 */
export const extractUser = async (req: Request, res: Response, next: NextFunction) => {
    try {
        const externalId = req.headers['x-auth-user-id'] as string;
        const organizationId = req.headers['x-organization-id'] as string;

        if (!externalId) {
            return next(); // No user, continue without
        }

        const user = await User.findOne({ externalId });

        if (user) {
            if (user.isBanned) {
                return res.status(403).json({ error: 'Conta bloqueada. Entre em contato com o administrador.' });
            }

            // Create extended user object
            const appUser: IAppUser = user.toObject() as IAppUser;
            appUser.organizationId = organizationId;

            // If organization context, get org-specific role
            if (organizationId) {
                // Check if Organization is globally banned (subscription specific, etc.)
                const orgStatus = await Organization.findOne({ externalId: organizationId });
                const orgName = req.headers['x-organization-name'] ? decodeURIComponent(req.headers['x-organization-name'] as string) : undefined;

                if (orgStatus) {
                    // Update name if different and present
                    if (orgName && orgStatus.name !== orgName) {
                        try {
                            await Organization.updateOne(
                                { externalId: organizationId },
                                { name: orgName }
                            );
                        } catch (err) {
                            console.warn('Failed to update organization name', err);
                        }
                    }

                    if (orgStatus.isBanned) {
                        return res.status(403).json({
                            error: 'Acesso bloqueado: Esta organização está suspensa. Entre em contato com o suporte.'
                        });
                    }
                } else {
                    // Create new org with name if present
                    try {
                        await Organization.create({
                            externalId: organizationId,
                            name: orgName
                        });
                    } catch (_e) {
                        console.warn('Organization auto-create race condition', _e);
                    }
                }

                const member = await OrganizationMember.findOne({ userId: externalId, organizationId });
                if (member) {
                    if (member.isBanned) {
                        return res.status(403).json({ error: 'Acesso bloqueado nesta organização.' });
                    }
                    appUser.organizationRole = member.role;
                    appUser.role = member.role; // Override global role with org role
                } else {
                    // User exists but is not a member of this org yet
                    appUser.organizationRole = 'guest';
                    appUser.role = 'guest';
                }
            }

            req.appUser = appUser;
            // console.log(`✅ Request authenticated as: ${appUser.name} (${appUser.role})`);
        } else {
            console.warn(`⚠️ User with Auth ID ${externalId} not found in MongoDB. Sync required.`);
        }

        next();
    } catch (error) {
        console.error('Error extracting user:', error);
        next();
    }
};

/**
 * Middleware to require specific roles for a route
 * @param allowedRoles Array of roles that can access the route
 */
export const requireRole = (allowedRoles: OrgRole[]) => {
    return (req: Request, res: Response, next: NextFunction) => {
        if (!req.appUser) {
            return res.status(401).json({ error: 'Autenticação necessária.' });
        }

        // DEV Bypass: Developer has full power
        if (req.appUser.email === 'admtracksteel@gmail.com') {
            return next();
        }

        const effectiveRole = req.appUser.organizationRole || req.appUser.role;

        if (!allowedRoles.includes(effectiveRole as OrgRole)) {
            return res.status(403).json({ error: 'Acesso negado. Permissões insuficientes.' });
        }

        next();
    };
};

/**
 * Middleware to require admin role
 */
export const requireAdmin = requireRole(['admin']);

/**
 * Middleware to require at least user role (user or admin)
 */
export const requireUser = requireRole(['user', 'admin']);

/**
 * Middleware to check if user can edit (user or admin, not guest)
 */
export const canEdit = (req: Request, res: Response, next: NextFunction) => {
    if (!req.appUser) {
        return res.status(401).json({ error: 'Autenticação necessária.' });
    }

    const effectiveRole = req.appUser.organizationRole || req.appUser.role;

    if (effectiveRole === 'guest') {
        return res.status(403).json({ error: 'Convidados não podem editar. Solicite acesso ao administrador.' });
    }

    next();
};

/**
 * Middleware to require Developer (Super Admin) access
 * Hardcoded to specific email for security
 */
export const requireDeveloper = (req: Request, res: Response, next: NextFunction) => {
    if (!req.appUser) {
        return res.status(401).json({ error: 'Autenticação necessária.' });
    }

    if (req.appUser.email !== 'admtracksteel@gmail.com') {
        console.warn(`⛔ Attempted unauthorized developer access by: ${req.appUser.email}`);
        return res.status(403).json({ error: 'Acesso restrito ao desenvolvedor.' });
    }

    next();
};
