import { Request, Response, NextFunction } from 'express';
// @ts-ignore – Staffbase SDK v1.x hat keine vollständigen TypeScript Typen
import staffbaseSDK from '@staffbase/staffbase-plugin-sdk';
// Im SDK v1.x ist `middleware` direkt die ssoMiddleWare-Funktion
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { middleware: ssoMiddleWare } = require('@staffbase/staffbase-plugin-sdk');
import { logger } from '../services/logger';

// ============================================================
// Staffbase SDK Typen (v1.x)
// Das SDK gibt req.sbSSO als SSOTokenData-Objekt zurück
// ============================================================
export interface SBSSOData {
  sub: string;              // userId
  name?: string;            // full name
  given_name?: string;      // first name
  family_name?: string;     // last name
  locale?: string;          // z.B. "de_DE"
  branch_id?: string;       // Branch/Abteilung
  role?: string;            // "editor" | "viewer" etc.
  aud?: string;             // Plugin-Audience
  exp?: number;
  iat?: number;
  primary_email_address?: string;
  username?: string;
}

// Express Request um sbSSO-Feld erweitern
declare global {
  namespace Express {
    interface Request {
      sbSSO?: SBSSOData;
      staffbaseUser?: SBSSOData; // Alias für komfortableren Zugriff
    }
  }
}

/**
 * Staffbase SSO Middleware (SDK v1.x)
 *
 * Das SDK validiert den JWT (?jwt= Query-Parameter) automatisch
 * und hängt die dekodierten User-Daten als req.sbSSO an.
 *
 * Wir wrappen das in unsere eigene Middleware, die:
 * 1. Das SDK aufruft
 * 2. req.staffbaseUser als bequemen Alias setzt
 * 3. Bei fehlendem/ungültigem Token 401 zurückgibt
 */
export const staffbaseAuth = (pluginSecret?: string, audience?: string) => {
  // SDK-Middleware initialisieren
  // Secret = RSA Public Key aus STAFFBASE_PUBLIC_KEY env var
  // Audience = Plugin-ID aus STAFFBASE_PLUGIN_ID env var (optional)
  const sdkSecret = pluginSecret ?? process.env.STAFFBASE_PUBLIC_KEY ?? '';
  const sdkAudience = audience ?? process.env.STAFFBASE_PLUGIN_ID ?? '';

  const sdkMiddleware = ssoMiddleWare(sdkSecret, sdkAudience);

  return (req: Request, res: Response, next: NextFunction): void => {
    // Token muss vorhanden sein (Query-Param oder Authorization Header)
    const hasToken =
      req.query.jwt ||
      req.headers.authorization?.startsWith('Bearer ');

    if (!hasToken) {
      res.status(401).json({
        error: 'Unauthorized',
        message: 'Kein JWT-Token gefunden. Bitte über Staffbase aufrufen.',
      });
      return;
    }

    // Authorization Header → in Query-Param umwandeln (SDK erwartet ?jwt=)
    if (!req.query.jwt && req.headers.authorization) {
      const token = req.headers.authorization.replace('Bearer ', '');
      (req.query as Record<string, string>).jwt = token;
    }

    // SDK-Middleware aufrufen (setzt req.sbSSO bei Erfolg)
    sdkMiddleware(req, res, () => {
      if (!req.sbSSO || !req.sbSSO.sub) {
        logger.warn('JWT validation failed or token missing', {
          path: req.path,
          ip: req.ip,
        });
        res.status(401).json({
          error: 'Unauthorized',
          message: 'Ungültiger oder abgelaufener JWT-Token.',
        });
        return;
      }

      // Alias setzen
      req.staffbaseUser = req.sbSSO;

      logger.debug('Staffbase JWT validated', {
        userId: req.staffbaseUser.sub,
        name: req.staffbaseUser.name,
        role: req.staffbaseUser.role,
      });

      next();
    });
  };
};

/**
 * Requires editor role for admin actions.
 * Must be used after staffbaseAuth middleware.
 */
export const requireEditor = (
  req: Request,
  res: Response,
  next: NextFunction
): void => {
  if (!req.staffbaseUser || req.staffbaseUser.role !== 'editor') {
    res.status(403).json({
      error: 'Forbidden',
      message: 'Editor-Rolle erforderlich.',
    });
    return;
  }
  next();
};
