import { Request, Response } from 'express';
import { permissionService } from '../services/permission.service';
import pool from '../config/database';
import logger from '../utils/logger';

class PermissionController {
  /**
   * GET /api/permissions/me
   * Returns the current user's effective permissions.
   */
  async getMyPermissions(req: Request, res: Response): Promise<void> {
    try {
      const groups: string[] = req.user?.groups ?? [];
      const isAdmin = groups.includes('dashboard_admin');

      let permissions: string[];
      if (isAdmin) {
        // Admin gets all permissions
        const matrix = await permissionService.getMatrix();
        permissions = matrix.permissions.map(p => p.id);
      } else {
        permissions = permissionService.getEffectivePermissions(groups);
      }

      const maintenance = permissionService.getMaintenanceFlags();

      logger.debug('GET /api/permissions/me', {
        email: req.user?.email,
        groups,
        isAdmin,
        permissionsCount: permissions.length,
        maintenanceWissen: maintenance['wissen'] ?? false,
        maintenanceAusruestungsanfrage: maintenance['ausruestungsanfrage'] ?? false,
      });

      res.json({
        success: true,
        data: {
          permissions,
          maintenance,
          isAdmin,
        },
      });
    } catch (error) {
      logger.error('Failed to get user permissions', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Berechtigungen' });
    }
  }

  /**
   * GET /api/admin/permissions/matrix
   * Returns the full permission matrix for the admin UI.
   */
  async getMatrix(_req: Request, res: Response): Promise<void> {
    try {
      const matrix = await permissionService.getMatrix();
      res.json({ success: true, data: matrix });
    } catch (error) {
      logger.error('Failed to get permission matrix', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Berechtigungsmatrix' });
    }
  }

  /**
   * PUT /api/admin/permissions/group/:groupName
   * Sets all permissions for a given Authentik group.
   */
  async setGroupPermissions(req: Request, res: Response): Promise<void> {
    try {
      const groupName = req.params.groupName as string;
      const { permissions } = req.body;

      if (!Array.isArray(permissions)) {
        res.status(400).json({ success: false, message: 'permissions must be an array' });
        return;
      }

      await permissionService.setGroupPermissions(
        groupName,
        permissions,
        req.user!.id
      );

      res.json({ success: true, message: 'Berechtigungen aktualisiert' });
    } catch (error) {
      logger.error('Failed to set group permissions', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Speichern der Berechtigungen' });
    }
  }

  /**
   * DELETE /api/admin/permissions/group/:groupName
   * Removes a group and all its permissions from the matrix.
   */
  async deleteGroup(req: Request, res: Response): Promise<void> {
    try {
      const groupName = req.params.groupName as string;
      await permissionService.deleteGroup(groupName);
      res.json({ success: true, message: 'Gruppe entfernt' });
    } catch (error) {
      logger.error('Failed to delete group', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Entfernen der Gruppe' });
    }
  }

  /**
   * PUT /api/admin/permissions/bulk
   * Bulk-update permissions for multiple groups in one request.
   * Body: { updates: [{ group: string, permissions: string[] }] }
   */
  async setBulkPermissions(req: Request, res: Response): Promise<void> {
    try {
      const { updates } = req.body;

      if (!Array.isArray(updates)) {
        res.status(400).json({ success: false, message: 'updates must be an array' });
        return;
      }

      for (const u of updates) {
        if (typeof u.group !== 'string' || !Array.isArray(u.permissions)) {
          res.status(400).json({ success: false, message: 'Each update must have group (string) and permissions (array)' });
          return;
        }
      }

      const result = await permissionService.setMultipleGroupPermissions(updates, req.user!.id);
      if (result.droppedPermissions.length > 0) {
        res.json({
          success: true,
          message: `Berechtigungen aktualisiert. Warnung: ${result.droppedPermissions.length} Berechtigung(en) existieren nicht in der Datenbank und wurden ignoriert: ${result.droppedPermissions.join(', ')}`,
          droppedPermissions: result.droppedPermissions,
        });
      } else {
        res.json({ success: true, message: 'Berechtigungen aktualisiert' });
      }
    } catch (error) {
      logger.error('Failed to set bulk permissions', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Speichern der Berechtigungen' });
    }
  }

  /**
   * GET /api/admin/permissions/groups
   * Returns all known Authentik groups from the permission table.
   */
  async getGroups(_req: Request, res: Response): Promise<void> {
    try {
      const groups = await permissionService.getKnownGroups();
      res.json({ success: true, data: groups });
    } catch (error) {
      logger.error('Failed to get groups', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Gruppen' });
    }
  }

  /**
   * GET /api/admin/permissions/unknown-groups
   * Returns Authentik groups found in users table but not in the permission matrix.
   */
  async getUnknownGroups(_req: Request, res: Response): Promise<void> {
    try {
      const groups = await permissionService.getUnknownGroups();
      res.json({ success: true, data: groups });
    } catch (error) {
      logger.error('Failed to get unknown groups', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der unbekannten Gruppen' });
    }
  }

  /**
   * PUT /api/admin/permissions/maintenance/:featureGroupId
   * Toggles maintenance mode for a feature group.
   */
  async setMaintenanceFlag(req: Request, res: Response): Promise<void> {
    try {
      const featureGroupId = req.params.featureGroupId as string;
      const { active } = req.body;

      if (typeof active !== 'boolean') {
        res.status(400).json({ success: false, message: 'active must be a boolean' });
        return;
      }

      await permissionService.setMaintenanceFlag(featureGroupId, active);
      res.json({ success: true, message: 'Wartungsmodus aktualisiert' });
    } catch (error) {
      logger.error('Failed to set maintenance flag', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Setzen des Wartungsmodus' });
    }
  }

  /**
   * GET /api/admin/permissions/config
   * Returns the dependency configuration (group hierarchy + permission deps).
   */
  async getDependencyConfig(_req: Request, res: Response): Promise<void> {
    try {
      const config = await permissionService.getDependencyConfig();
      res.json({ success: true, data: config });
    } catch (error) {
      logger.error('Failed to get dependency config', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Konfiguration' });
    }
  }

  /**
   * PUT /api/admin/permissions/config
   * Updates the dependency configuration.
   * Body: { groupHierarchy?: Record<string, string[]>, permissionDeps?: Record<string, string[]> }
   */
  async setDependencyConfig(req: Request, res: Response): Promise<void> {
    try {
      const { groupHierarchy, permissionDeps } = req.body;

      if (groupHierarchy !== undefined) {
        if (typeof groupHierarchy !== 'object' || groupHierarchy === null) {
          res.status(400).json({ success: false, message: 'groupHierarchy must be an object' });
          return;
        }
        await permissionService.setGroupHierarchy(groupHierarchy, req.user!.id);
      }

      if (permissionDeps !== undefined) {
        if (typeof permissionDeps !== 'object' || permissionDeps === null) {
          res.status(400).json({ success: false, message: 'permissionDeps must be an object' });
          return;
        }
        await permissionService.setPermissionDeps(permissionDeps, req.user!.id);
      }

      res.json({ success: true, message: 'Konfiguration aktualisiert' });
    } catch (error) {
      logger.error('Failed to set dependency config', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Speichern der Konfiguration' });
    }
  }

  /**
   * GET /api/permissions/users-with?permission=bestellungen:create
   * Returns users who have a specific permission.
   */
  async getUsersWithPermission(req: Request, res: Response): Promise<void> {
    try {
      const permission = req.query.permission as string;
      if (!permission) {
        res.status(400).json({ success: false, message: 'permission query parameter required' });
        return;
      }
      const users = await permissionService.getUsersWithPermission(permission);
      res.json({ success: true, data: users });
    } catch (error) {
      logger.error('Failed to get users with permission', { error });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Benutzer' });
    }
  }
  /**
   * GET /api/permissions/debug/:userId
   * Returns debug info for a specific user: their groups, resolved permissions,
   * and maintenance flags. Admin only.
   */
  async debugUser(req: Request, res: Response): Promise<void> {
    try {
      const userId = req.params.userId as string;

      // Fetch user's Authentik groups from DB
      const userResult = await pool.query(
        'SELECT authentik_groups, email, name FROM users WHERE id = $1',
        [userId]
      );

      if (userResult.rows.length === 0) {
        res.status(404).json({ success: false, message: 'Benutzer nicht gefunden' });
        return;
      }

      const user = userResult.rows[0];
      const groups: string[] = user.authentik_groups ?? [];
      const isAdmin = groups.includes('dashboard_admin');

      // Resolve permissions for those groups
      let permissions: string[];
      if (isAdmin) {
        const matrix = await permissionService.getMatrix();
        permissions = matrix.permissions.map(p => p.id);
      } else {
        permissions = permissionService.getEffectivePermissions(groups);
      }

      // Maintenance flags
      const maintenance = permissionService.getMaintenanceFlags();
      const maintenanceActive = Object.entries(maintenance)
        .filter(([, active]) => active)
        .map(([featureGroup]) => featureGroup);

      res.json({
        success: true,
        data: {
          userId,
          email: user.email,
          name: user.name,
          authentikGroups: groups,
          isAdmin,
          permissions,
          maintenance,
          maintenanceActiveFeatureGroups: maintenanceActive,
        },
      });
    } catch (error) {
      logger.error('Failed to debug user permissions', { error, userId: req.params.userId });
      res.status(500).json({ success: false, message: 'Fehler beim Laden der Debug-Informationen' });
    }
  }
}

export default new PermissionController();
