import { type LinkAction, type Links } from 'src/types/actionLinks';

/** Backend `_links` keys: direct edit or request-edit (approval) flow. */
export const EDIT_ACTIONS = ['edit', 'requestEdit'] as const;

/** Backend `_links` key for requesting an edit that goes through approval. */
export const REQUEST_EDIT_ACTIONS = ['requestEdit'] as const;

const isLinkAction = (value: unknown): value is LinkAction => {
  if (!value || typeof value !== 'object') return false;
  const candidate = value as { href?: unknown; method?: unknown };
  return (
    typeof candidate.href === 'string' && typeof candidate.method === 'string'
  );
};

export const canPerformAction = (links: Links, action: string): boolean =>
  !!links?.[action];

export const hasActionLinks = (links?: Links): boolean =>
  !!links && Object.keys(links).length > 0;

export const canPerformAnyAction = (
  links: Links,
  actions: readonly string[],
): boolean => actions.some(action => canPerformAction(links, action));

/**
 * Backend may return menu actions under `_links` or as top-level `LinkAction` objects.
 * This normalizes both response shapes.
 */
export const extractActionLinks = (
  resource?: {
    _links?: Links;
  } & Record<string, unknown>,
): Links => {
  if (!resource) return {};
  // If `_links` key is explicitly present, respect it and do not fallback-scan.
  if (Object.prototype.hasOwnProperty.call(resource, '_links')) {
    return hasActionLinks(resource._links) ? (resource._links as Links) : {};
  }

  return Object.entries(resource).reduce<Links>((acc, [key, value]) => {
    if (isLinkAction(value)) acc[key] = value;
    return acc;
  }, {});
};
