import { applyDecorators, UseGuards } from '@nestjs/common';
import { JwtGuard } from '@tria-plc/api-common/modules/auth/services/jwt.guard';

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

export const BookingStaff = (permission: string | string[]) =>
  applyDecorators(
    UseGuards(
      JwtGuard,
      FreightPermissionGuard(
        Array.isArray(permission) ? permission : [permission],
      ),
    ),
  );

/**
 * Read-only reference data (yard dropdowns, search filters): any signed-in
 * staff. Menu/page visibility stays permission-gated in the frontend — this
 * only lets forms populate their lookups.
 */
export const StaffReference = () => applyDecorators(UseGuards(JwtGuard));

export const BookingView = () => BookingStaff(FREIGHT_PERMS.bookings.view);

/**
 * The document-review countdown in the backoffice header. Its own permission so
 * it can be granted to exactly the position types that decide operation
 * requests, instead of every holder of bookings:view.
 */
export const BookingDocReviewAlert = () =>
  BookingStaff(FREIGHT_PERMS.bookings.docReviewAlert);

export const TrainSchedulingView = () =>
  BookingStaff(FREIGHT_PERMS.trainScheduling.view);

// Granular train-scheduling actions replace the retired coarse manage:
// create a schedule, update (assign/consist/loading/finalize/dispatch/arrive…),
// cancel a schedule, reschedule (+ maintenance), and manage global rules.
export const TrainSchedulingCreate = () =>
  BookingStaff(FREIGHT_PERMS.trainScheduling.create);

export const TrainSchedulingUpdate = () =>
  BookingStaff(FREIGHT_PERMS.trainScheduling.update);

export const TrainSchedulingCancel = () =>
  BookingStaff(FREIGHT_PERMS.trainScheduling.cancel);

export const TrainSchedulingReschedule = () =>
  BookingStaff(FREIGHT_PERMS.trainScheduling.reschedule);

export const TrainSchedulingRulesManage = () =>
  BookingStaff(FREIGHT_PERMS.trainScheduling.rulesManage);

/**
 * Fleet guards take an optional granular per-resource key (locomotives:create,
 * wagons:delete, …). The legacy coarse fleet:view / fleet:manage keys remain
 * valid as a one-of fallback so existing role grants keep working.
 */
export const FleetView = (granular?: string) =>
  BookingStaff(
    granular ? [granular, FREIGHT_PERMS.fleet.view] : FREIGHT_PERMS.fleet.view,
  );

export const FleetManage = (granular?: string) =>
  BookingStaff(
    granular
      ? [granular, FREIGHT_PERMS.fleet.manage]
      : FREIGHT_PERMS.fleet.manage,
  );

/** Requester creates a wagon-transfer request (count-only, no wagon picks). */
export const WagonTransferRequest = () =>
  BookingStaff(FREIGHT_PERMS.wagons.transferRequest);

/** OCC fulfils a wagon-transfer request — picks the wagons and executes the move. */
export const WagonTransferFulfill = () =>
  BookingStaff(FREIGHT_PERMS.wagons.transferFulfill);

/** Admin: read every staffer's wagon-transfer history (not just one's own). */
export const WagonTransferHistoryAll = () =>
  BookingStaff(FREIGHT_PERMS.wagons.transferHistoryAll);

/**
 * Open the transfer-requests desk. `wagons:view` is accepted as a one-of
 * fallback so staff who could already reach the queue keep it without a
 * re-grant — same pattern the granular fleet keys use.
 */
export const WagonTransferView = () =>
  BookingStaff([FREIGHT_PERMS.wagons.transferView, FREIGHT_PERMS.wagons.view]);

/** Withdraw a request that has not moved any wagon yet. */
export const WagonTransferCancel = () =>
  BookingStaff([
    FREIGHT_PERMS.wagons.transferCancel,
    FREIGHT_PERMS.wagons.transferRequest,
  ]);

/**
 * End a request short of the requested count. Whoever may move wagons may also
 * declare the yard has no more to give, so fulfil is accepted alongside the
 * dedicated key.
 */
export const WagonTransferCloseShort = () =>
  BookingStaff([
    FREIGHT_PERMS.wagons.transferCloseShort,
    FREIGHT_PERMS.wagons.transferFulfill,
  ]);

/** Org-administration endpoints (user mgmt, billing config, company CRUD, settings). */
export const FreightAdmin = () => BookingStaff(FREIGHT_PERMS.admin);

/** Container allocation on a booking (allocate-containers endpoint). */
export const AllocationManage = () =>
  BookingStaff(FREIGHT_PERMS.allocation.manage);
