// Small builders that keep the OpenAPI path files readable. Every JSON
// endpoint answers with the envelope produced by utils/apiResponse.sendResponse:
// { success, status_code, message, data, errors, pagination }.

type Schema = Record<string, unknown>;

// ─── Security ────────────────────────────────────────────────────────────────

// protectAdmin — access token from POST /api/auth/admin/login or /api/auth/verify-otp
export const ADMIN_AUTH = [{ AdminBearerAuth: [] }];
// protectUser — access token from POST /api/auth/user/login (Employee App and Tracker App)
export const USER_AUTH = [{ UserBearerAuth: [] }];
// No auth
export const PUBLIC: unknown[] = [];

// ─── Schema shorthands ───────────────────────────────────────────────────────

export const ref = (name: string): Schema => ({ $ref: `#/components/schemas/${name}` });
export const arr = (items: Schema): Schema => ({ type: 'array', items });
export const obj = (properties: Record<string, Schema>, required?: string[]): Schema => ({
  type: 'object',
  properties,
  ...(required && required.length ? { required } : {}),
});

export const str = (example?: unknown, extra: Schema = {}): Schema => ({
  type: 'string',
  ...(example !== undefined ? { example } : {}),
  ...extra,
});
export const int = (example?: unknown, extra: Schema = {}): Schema => ({
  type: 'integer',
  ...(example !== undefined ? { example } : {}),
  ...extra,
});
export const num = (example?: unknown, extra: Schema = {}): Schema => ({
  type: 'number',
  ...(example !== undefined ? { example } : {}),
  ...extra,
});
export const bool = (example?: unknown, extra: Schema = {}): Schema => ({
  type: 'boolean',
  ...(example !== undefined ? { example } : {}),
  ...extra,
});
export const dateTime = (extra: Schema = {}): Schema => ({ type: 'string', format: 'date-time', ...extra });
export const objectId = (description?: string): Schema => ({
  type: 'string',
  example: '663f1a2b3c4d5e6f7a8b9c0d',
  ...(description ? { description } : {}),
});
// Loosely-typed object (Mongoose document returned as-is)
export const anyObj = (description?: string): Schema => ({
  type: 'object',
  additionalProperties: true,
  ...(description ? { description } : {}),
});

// ─── Parameters ──────────────────────────────────────────────────────────────

export const pathParam = (name: string, description?: string, schema: Schema = { type: 'string' }) => ({
  name,
  in: 'path',
  required: true,
  schema,
  ...(description ? { description } : {}),
});

export const queryParam = (name: string, schema: Schema, description?: string, required = false) => ({
  name,
  in: 'query',
  required,
  schema,
  ...(description ? { description } : {}),
});

export const pageParam = queryParam('page', { type: 'integer', minimum: 1, default: 1 }, 'Page number (1-based)');
export const limitParam = (defaultLimit: number, max?: number) =>
  queryParam(
    'limit',
    { type: 'integer', minimum: 1, default: defaultLimit, ...(max ? { maximum: max } : {}) },
    max ? `Page size (values above ${max} are clamped)` : 'Page size',
  );

// ─── Request bodies ──────────────────────────────────────────────────────────

export const jsonBody = (schema: Schema, required = true) => ({
  required,
  content: { 'application/json': { schema } },
});

export const multipartBody = (schema: Schema) => ({
  required: true,
  content: { 'multipart/form-data': { schema } },
});

// ─── Responses ───────────────────────────────────────────────────────────────

const NULL_FIELD = { nullable: true, example: null };

// Success response wrapped in the standard envelope.
export const ok = (
  message: string,
  data: Schema | null = null,
  opts: { status?: number; paginated?: boolean; description?: string } = {},
) => {
  const status = opts.status ?? 200;
  return {
    [status]: {
      description: opts.description ?? message,
      content: {
        'application/json': {
          schema: obj({
            success: bool(true),
            status_code: int(status),
            message: str(message),
            data: data ?? NULL_FIELD,
            errors: { type: 'string', ...NULL_FIELD },
            pagination: opts.paginated ? ref('Pagination') : { type: 'object', ...NULL_FIELD },
          }),
        },
      },
    },
  };
};

export const created = (message: string, data: Schema | null = null) => ok(message, data, { status: 201 });
export const paginated = (message: string, data: Schema) => ok(message, data, { paginated: true });

// Error response(s) with the standard envelope (success: false, data: null).
export const err = (status: number, description: string) => ({
  [status]: {
    description,
    content: { 'application/json': { schema: ref('ErrorResponse') } },
  },
});

export const errs = (map: Record<number, string>) =>
  Object.entries(map).reduce((acc, [status, description]) => ({ ...acc, ...err(Number(status), description) }), {});

export const ADMIN_ERRORS = errs({
  401: 'Missing, invalid or expired admin access token',
  403: 'Token does not belong to an admin',
});

export const USER_ERRORS = errs({
  401: 'Missing, invalid or expired employee access token',
  403: 'Token does not belong to an employee',
});
