import { HttpException, HttpStatus } from '@nestjs/common';

/**
 * Business rule violations carry a stable machine-readable code so that the
 * web app and integrations can react to them without parsing messages.
 */
export class DomainError extends HttpException {
  constructor(
    public readonly code: string,
    message: string,
    status: HttpStatus = HttpStatus.UNPROCESSABLE_ENTITY,
    public readonly details?: unknown,
  ) {
    super({ statusCode: status, error: 'DomainError', code, message, details }, status);
  }
}

export class NotFoundError extends DomainError {
  constructor(entity: string, id?: string) {
    super('NOT_FOUND', id ? `${entity} ${id} not found` : `${entity} not found`, HttpStatus.NOT_FOUND);
  }
}

export class ConflictError extends DomainError {
  constructor(code: string, message: string, details?: unknown) {
    super(code, message, HttpStatus.CONFLICT, details);
  }
}

export class ForbiddenError extends DomainError {
  constructor(message = 'Forbidden', code = 'FORBIDDEN') {
    super(code, message, HttpStatus.FORBIDDEN);
  }
}

export class ValidationError extends DomainError {
  constructor(message: string, details?: unknown) {
    super('VALIDATION_ERROR', message, HttpStatus.BAD_REQUEST, details);
  }
}

/** Common error codes used across modules. */
export const ErrorCodes = {
  INVALID_STATE: 'INVALID_STATE',
  INSUFFICIENT_STOCK: 'INSUFFICIENT_STOCK',
  LOCATION_BLOCKED: 'LOCATION_BLOCKED',
  LOCATION_CAPACITY: 'LOCATION_CAPACITY',
  MIXING_NOT_ALLOWED: 'MIXING_NOT_ALLOWED',
  LOT_REQUIRED: 'LOT_REQUIRED',
  EXPIRY_REQUIRED: 'EXPIRY_REQUIRED',
  SERIAL_REQUIRED: 'SERIAL_REQUIRED',
  SERIAL_DUPLICATE: 'SERIAL_DUPLICATE',
  SERIAL_NOT_FOUND: 'SERIAL_NOT_FOUND',
  SHELF_LIFE_BELOW_MIN: 'SHELF_LIFE_BELOW_MIN',
  OVER_RECEIPT: 'OVER_RECEIPT',
  TASK_NOT_OWNED: 'TASK_NOT_OWNED',
  WRONG_LOCATION: 'WRONG_LOCATION',
  WRONG_SKU: 'WRONG_SKU',
  WRONG_LPN: 'WRONG_LPN',
  DUPLICATE: 'DUPLICATE',
  PLAN_LIMIT: 'PLAN_LIMIT',
  FEATURE_DISABLED: 'FEATURE_DISABLED',
  AI_DISABLED: 'AI_DISABLED',
  CONTRACT_MISSING: 'CONTRACT_MISSING',
} as const;
