import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import { config } from '../../config';
import { AppError } from './errorHandler';
import prisma from '../../config/database';

export interface EffectivePermission {
  module: string;
  resource: string;
  actions: string[];
}

function mergePermissions(
  positionPerms: { module: string; resource: string; actions: unknown }[],
  rolePerms: { module: string; resource: string; actions: unknown }[]
): EffectivePermission[] {
  const key = (m: string, r: string) => `${m}:${r}`;
  const map = new Map<string, Set<string>>();

  const add = (m: string, r: string, actions: unknown) => {
    const arr = Array.isArray(actions) ? actions : [];
    const actionSet = new Set<string>(arr.map(String));
    const k = key(m, r);
    const existing = map.get(k);
    if (existing) {
      actionSet.forEach((a) => existing.add(a));
    } else {
      map.set(k, actionSet);
    }
  };

  (positionPerms || []).forEach((p) => add(p.module, p.resource, p.actions));
  (rolePerms || []).forEach((p) => add(p.module, p.resource, p.actions));

  return Array.from(map.entries()).map(([k, actions]) => {
    const [module, resource] = k.split(':');
    return { module, resource, actions: Array.from(actions) };
  });
}

export interface AuthRequest extends Request {
  user?: {
    id: string;
    email: string;
    employeeId?: string;
    employee?: any;
    effectivePermissions?: EffectivePermission[];
  };
}

export const authenticate = async (
  req: AuthRequest,
  res: Response,
  next: NextFunction
) => {
  try {
    // Get token from header
    const authHeader = req.headers.authorization;
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      throw new AppError(401, 'غير مصرح - Unauthorized');
    }

    const token = authHeader.split(' ')[1];

    // Verify token
    const decoded = jwt.verify(token, config.jwt.secret) as {
      id: string;
      email: string;
    };

    // Get user with employee + roles (Phase 3: multi-group)
    const user = await prisma.user.findUnique({
      where: { id: decoded.id },
      include: {
        employee: {
          include: {
            position: {
              include: {
                permissions: true,
              },
            },
            department: true,
          },
        },
        userRoles: {
          where: { role: { isActive: true } },
          include: {
            role: {
              include: { permissions: true },
            },
          },
        },
      },
    });

    if (!user || !user.isActive) {
      throw new AppError(401, 'غير مصرح - Unauthorized');
    }

    // HR module requirement: User must have an active employee record
    if (!user.employee || user.employee.status !== 'ACTIVE') {
      throw new AppError(403, 'الوصول مرفوض - Access denied. Active employee record required.');
    }

    const positionPerms = user.employee?.position?.permissions ?? [];
    const rolePerms = (user as any).userRoles?.flatMap(
      (ur: any) => ur.role?.permissions ?? []
    ) ?? [];
    const effectivePermissions = mergePermissions(positionPerms, rolePerms);

    req.user = {
      id: user.id,
      email: user.email,
      employeeId: user.employeeId || undefined,
      employee: user.employee,
      effectivePermissions,
    };

    next();
  } catch (error) {
    if (error instanceof jwt.JsonWebTokenError) {
      return next(new AppError(401, 'رمز غير صالح - Invalid token'));
    }
    next(error);
  }
};

// Permission checking middleware (Position + Role permissions merged)
export const authorize = (module: string, resource: string, action: string) => {
  return async (req: AuthRequest, res: Response, next: NextFunction) => {
    try {
      const perms = req.user?.effectivePermissions;
      if (!perms || perms.length === 0) {
        throw new AppError(403, 'الوصول مرفوض - Access denied');
      }

      const permission = perms.find(
        (p) => p.module === module && (p.resource === resource || p.resource === '*' || p.resource === 'all')
      );

      if (!permission) {
        throw new AppError(403, 'الوصول مرفوض - Access denied');
      }

      const actions = permission.actions;
      if (!actions.includes(action) && !actions.includes('*') && !actions.includes('all')) {
        throw new AppError(403, 'الوصول مرفوض - Access denied');
      }

      next();
    } catch (error) {
      next(error);
    }
  };
};

