import { ForbiddenException } from '@nestjs/common';
import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type';

import { FREIGHT_PERMS } from '../seed/freight-permissions.registry';

const SUPER_ADMIN_ROLE = 'super_admin';
const ORGANIZATION_ADMIN_ROLE = 'organization_admin';

type PermissionLike = { key?: string };
type MeLikeUser = {
  roles?: { key?: string }[];
  permissions?: PermissionLike[];
  employee?:
    | {
        position?: { permissions?: PermissionLike[] };
        delegatedPositions?: { permissions?: PermissionLike[] }[];
      }
    | {
        positions?: { permissions?: PermissionLike[] }[];
      }[]
    | null;
};

export function isSuperAdmin(user: MeLikeUser | null | undefined): boolean {
  if (!user?.roles?.length) return false;
  return user.roles.some((r) => r.key === SUPER_ADMIN_ROLE);
}

export function isOrganizationAdmin(user: MeLikeUser | null | undefined): boolean {
  if (!user?.roles?.length) return false;
  return user.roles.some((r) => r.key === ORGANIZATION_ADMIN_ROLE);
}

export function isFreightApprovalAdmin(user: MeLikeUser | null | undefined): boolean {
  return isSuperAdmin(user) || isOrganizationAdmin(user);
}

/** Flat permission keys from JWT / session user (roles + position permissions). */
export function collectPermissionKeys(user: MeLikeUser | null | undefined): string[] {
  if (!user) return [];

  const keys = new Set<string>();

  for (const p of user.permissions ?? []) {
    if (p.key) keys.add(p.key);
  }

  const employee = user.employee;
  if (!employee) {
    return [...keys];
  }

  if (Array.isArray(employee)) {
    for (const emp of employee) {
      for (const pos of emp.positions ?? []) {
        for (const p of pos.permissions ?? []) {
          if (p.key) keys.add(p.key);
        }
      }
    }
    return [...keys];
  }

  for (const p of employee.position?.permissions ?? []) {
    if (p.key) keys.add(p.key);
  }
  for (const delegated of employee.delegatedPositions ?? []) {
    for (const p of delegated.permissions ?? []) {
      if (p.key) keys.add(p.key);
    }
  }

  return [...keys];
}

export function hasFreightPermission(
  user: MeLikeUser | null | undefined,
  permissionKey: string,
): boolean {
  if (!user) return false;
  if (isSuperAdmin(user)) return true;
  return collectPermissionKeys(user).includes(permissionKey);
}

export function assertFreightPermission(
  user: TCurrentUser | MeLikeUser | null | undefined,
  permissionKey: string,
): void {
  if (hasFreightPermission(user, permissionKey)) return;
  throw new ForbiddenException(`Missing permission: ${permissionKey}`);
}

const APPROVE_ROLE_PERMISSION: Record<string, string> = {
  LINE_STAFF: FREIGHT_PERMS.bookings.approveLineStaff,
  DIRECTOR: FREIGHT_PERMS.bookings.approveDirector,
  CEO: FREIGHT_PERMS.bookings.approveCeo,
};

export function assertCanApproveBookingStep(
  user: TCurrentUser | MeLikeUser | null | undefined,
  requiredRole: string,
): void {
  if (isFreightApprovalAdmin(user)) return;
  const perm = APPROVE_ROLE_PERMISSION[requiredRole];
  if (!perm) {
    throw new ForbiddenException(`Unknown approval role: ${requiredRole}`);
  }
  assertFreightPermission(user, perm);
}
