// The access contract shared with the tenant app (config/modules.ts,
// config/permissions.ts, mocks/roles.ts), the super admin and mobile.
// Change module keys, permission codes and the default role matrix together
// with those clients; the apps only hide UI, this backend enforces it.

export const MODULE_KEYS = [
  'tenant_admin', // Phase 2 — always on
  'project_core', // Phase 3 — always on
  'tasks',
  'planning',
  'documents',
  'boq',
  'contracts',
  'procurement',
  'execution',
  'quality',
  'contractor_billing',
  'finance',
  'reports',
  'ai_insights',
  'presales_crm',
  'postsales_crm',
] as const;

export type ModuleKey = (typeof MODULE_KEYS)[number];

// Display names, same as the tenant app's moduleLabels (config/navigation.ts).
export const MODULE_LABELS: Record<ModuleKey, string> = {
  tenant_admin: 'Administration',
  project_core: 'Project Core',
  tasks: 'Task Management',
  planning: 'Planning & Scheduling',
  documents: 'Drawings & Documents',
  boq: 'BOQ & Estimation',
  contracts: 'Contracts',
  procurement: 'Procurement & Materials',
  execution: 'Execution & Site',
  quality: 'Quality',
  contractor_billing: 'Contractor Billing',
  finance: 'Cost & Finance',
  reports: 'Reports & BI',
  ai_insights: 'AI Insights',
  presales_crm: 'Pre-Sales CRM',
  postsales_crm: 'Post-Sales CRM',
};

// Administration and Project Core can't be switched off per role.
export const ALWAYS_ON_MODULES: ModuleKey[] = ['tenant_admin', 'project_core'];

type Action = 'view' | 'manage' | 'approve';

interface PermissionGroup {
  module: ModuleKey;
  // One entry per resource: the permission code for each action it supports.
  resources: Partial<Record<Action, string>>[];
}

// Permission codes are `<module>.<resource>.<action>`, in roadmap order.
export const PERMISSION_CATALOG: PermissionGroup[] = [
  {
    module: 'tenant_admin',
    resources: [
      { manage: 'admin.organization.manage' },
      { view: 'admin.users.view', manage: 'admin.users.manage' },
      { view: 'admin.roles.view', manage: 'admin.roles.manage' },
    ],
  },
  {
    module: 'project_core',
    resources: [
      { view: 'project.projects.view', manage: 'project.projects.manage' },
      { manage: 'project.members.manage' },
    ],
  },
  { module: 'tasks', resources: [{ view: 'tasks.tasks.view', manage: 'tasks.tasks.manage' }] },
  {
    module: 'planning',
    resources: [{ view: 'planning.wbs.view', manage: 'planning.wbs.manage', approve: 'planning.wbs.approve' }],
  },
  {
    module: 'documents',
    resources: [{ view: 'documents.drawings.view', manage: 'documents.drawings.manage', approve: 'documents.drawings.approve' }],
  },
  {
    module: 'boq',
    resources: [{ view: 'boq.items.view', manage: 'boq.items.manage', approve: 'boq.items.approve' }],
  },
  {
    module: 'procurement',
    resources: [{ view: 'procurement.orders.view', manage: 'procurement.orders.manage', approve: 'procurement.orders.approve' }],
  },
  {
    module: 'execution',
    resources: [{ view: 'execution.site.view', manage: 'execution.site.record', approve: 'execution.site.approve' }],
  },
  {
    module: 'finance',
    resources: [{ view: 'finance.costs.view', manage: 'finance.costs.manage', approve: 'finance.costs.approve' }],
  },
  {
    module: 'presales_crm',
    resources: [{ view: 'presales.leads.view', manage: 'presales.leads.manage' }],
  },
];

// Every permission with its module, e.g. { name: 'planning.wbs.approve', module: 'planning' }.
export const PERMISSIONS = PERMISSION_CATALOG.flatMap((group) =>
  group.resources.flatMap((resource) =>
    Object.values(resource).map((name) => ({ name, module: group.module })),
  ),
);

type Level = 'full' | 'edit' | 'approve' | 'view';

const actionsFor: Record<Level, Action[]> = {
  full: ['view', 'manage', 'approve'],
  edit: ['view', 'manage'],
  approve: ['view', 'approve'],
  view: ['view'],
};

export interface DefaultRole {
  name: string;
  label: string;
  description: string;
  scope: 'all' | 'assigned';
  permissions: string[];
  modules: ModuleKey[];
}

function role(
  name: string,
  label: string,
  description: string,
  scope: DefaultRole['scope'],
  levels: Partial<Record<ModuleKey, Level>>,
): DefaultRole {
  const permissions = PERMISSION_CATALOG.flatMap((group) => {
    const level = levels[group.module];
    if (!level) return [];
    return group.resources.flatMap((resource) =>
      actionsFor[level].flatMap((action) => (resource[action] ? [resource[action]] : [])),
    );
  });
  const modules = Object.keys(levels).filter((m) => m !== 'tenant_admin') as ModuleKey[];
  return {
    name,
    label,
    description,
    scope,
    permissions,
    modules: Array.from(new Set<ModuleKey>(['project_core', ...modules])),
  };
}

const everything = Object.fromEntries(
  PERMISSION_CATALOG.map((group) => [group.module, 'full' as const]),
) as Record<ModuleKey, Level>;

export const ORG_ADMIN_ROLE = 'organization-admin';

// The roadmap's 10 default tenant roles ("RBAC from the beginning" in the
// Phase 1–2 design). Role `name`s match the existing seeded roles.
export const DEFAULT_ROLES: DefaultRole[] = [
  role(ORG_ADMIN_ROLE, 'Organization Admin', 'Full access to everything in the organization.', 'all', everything),
  role('director', 'Director', 'Sees everything and approves plans, BOQ, purchases and costs.', 'all', {
    tenant_admin: 'view', project_core: 'view', tasks: 'view', planning: 'approve', documents: 'approve',
    execution: 'view', boq: 'approve', procurement: 'approve', finance: 'approve', presales_crm: 'view',
  }),
  role('project-manager', 'Project Manager', 'Runs assigned projects and approves plans and site records.', 'assigned', {
    project_core: 'edit', tasks: 'edit', planning: 'approve', documents: 'approve', execution: 'approve',
    boq: 'view', procurement: 'view', finance: 'view',
  }),
  role('planning-manager', 'Planning Manager', 'Builds and maintains the WBS and schedule.', 'assigned', {
    project_core: 'view', tasks: 'edit', planning: 'edit', documents: 'edit', execution: 'view', boq: 'view',
  }),
  role('site-engineer', 'Site Engineer', 'Records daily work on site and updates tasks.', 'assigned', {
    project_core: 'view', tasks: 'edit', planning: 'view', documents: 'view', execution: 'edit',
  }),
  role('qs', 'QS', 'Quantity surveyor: owns the BOQ and measurements.', 'assigned', {
    project_core: 'view', tasks: 'edit', planning: 'view', documents: 'view', execution: 'view',
    boq: 'edit', procurement: 'view', finance: 'view',
  }),
  role('procurement', 'Procurement', 'Raises and manages purchase requests and orders.', 'all', {
    project_core: 'view', tasks: 'edit', execution: 'view', boq: 'view', procurement: 'edit', finance: 'view',
  }),
  role('accounts', 'Accounts', 'Budgets, costs and payments.', 'all', {
    project_core: 'view', tasks: 'edit', boq: 'view', procurement: 'view', finance: 'edit', presales_crm: 'view',
  }),
  role('sales-executive', 'Sales Executive', 'Leads, site visits and bookings.', 'all', {
    project_core: 'view', tasks: 'edit', presales_crm: 'edit',
  }),
  role('viewer', 'Viewer', 'Read-only access to assigned projects.', 'assigned', {
    project_core: 'view', tasks: 'view', planning: 'view', documents: 'view', execution: 'view', boq: 'view',
  }),
];

// Roles a person can hold on one project (separate from organization roles).
// Same list as the tenant app's config/projectRoles.ts.
export const PROJECT_ROLES = [
  'Project Manager',
  'Planner',
  'Site Engineer',
  'QS',
  'Quality Engineer',
  'Procurement',
  'Viewer',
] as const;

/** The closest project role for someone added to a project from their organization roles. */
export function projectRoleFor(roleLabels: string[]): string {
  const aliases: Record<string, string> = { 'Planning Manager': 'Planner' };
  for (const label of roleLabels) {
    const mapped = aliases[label] ?? label;
    if ((PROJECT_ROLES as readonly string[]).includes(mapped)) return mapped;
  }
  return 'Viewer';
}
