import DbApi from '@/db/api/staff';
import { createCrudService } from '@/services/shared/crud-service';
import { assertCanManageUserWithRole } from '@/services/shared/role-policy';
import { STAFF_TYPE_TO_ROLE_NAME } from '@/shared/constants/roles';
import { isRecord } from '@/shared/object';
import type { CurrentUser } from '@/db/api/types';

const base = createCrudService(DbApi, { notFoundCode: 'staffNotFound' });

/**
 * Relational policy on staff writes (Workstream 3 §3.3): a staff profile carries
 * a `staff_type` that maps to a campus role, so creating/updating one is
 * effectively managing a user with that role. Enforce the same role-hierarchy
 * rule used for the `users` write paths, so an actor cannot provision a staff
 * member of a role it is not allowed to manage (e.g. via a stray
 * `custom_permission` granting `CREATE_STAFF`). Tenant/campus scoping stays in
 * the data layer.
 */
function assertCanManageStaffRole(
  currentUser: CurrentUser | undefined,
  data: unknown,
): void {
  if (!isRecord(data) || typeof data.staff_type !== 'string') {
    return;
  }
  const role = STAFF_TYPE_TO_ROLE_NAME[data.staff_type];
  if (role) {
    assertCanManageUserWithRole(currentUser, role);
  }
}

const service: typeof base = {
  ...base,
  create(data, currentUser) {
    assertCanManageStaffRole(currentUser, data);
    return base.create(data, currentUser);
  },
  update(data, id, currentUser) {
    assertCanManageStaffRole(currentUser, data);
    return base.update(data, id, currentUser);
  },
};

export default service;
