import { destructureNacelleEntryId } from '.';
import { flattenContentfulMedia, isContentfulMedia } from './transformMedia';
import { isObject } from './transformContent';
import type { AnyObject, NacelleContentEntry } from '.';

interface ReconstructedContentfulEntry {
  fields: AnyObject;
  metadata: {
    tags: string[];
  };
  sys: {
    id: string;
    type: 'Entry';
    contentType: {
      sys: {
        id: string;
        linkType: 'ContentType';
        type: 'Link';
      };
    };
  };
}

export type ContentfulEntry = AnyObject & {
  fields: AnyObject;
  sys: AnyObject & { type: string; id: string };
};

const isContentfulEntry = (x: unknown): x is ContentfulEntry =>
  isObject((x as ContentfulEntry)?.fields) &&
  isObject((x as ContentfulEntry)?.sys);

export function flattenContentfulContent(entry: AnyObject): AnyObject {
  if (!isObject(entry?.fields)) {
    return entry;
  }

  const newEntry: AnyObject = {};

  for (const [key, value] of Object.entries(entry.fields)) {
    if (isContentfulMedia(value)) {
      newEntry[key] = flattenContentfulMedia(value);
    } else if (isContentfulEntry(value)) {
      newEntry[key] = flattenContentfulContent(value.fields);
    } else {
      newEntry[key] = value;
    }
  }

  if (isContentfulEntry(entry)) {
    // extract required properties from the `sys` object
    const { createdAt = 0, updatedAt = 0 } = entry.sys;
    newEntry.createdAt = createdAt;
    newEntry.updatedAt = updatedAt;
  } else {
    newEntry.createdAt = 0;
    newEntry.updatedAt = 0;
  }

  return flattenContentfulContent(newEntry);
}

/**
 * Reshapes a Nacelle v2 content entry reference to a Contentful entry format.
 * There are properties of `sys` that we can't reconstruct from a Nacelle v2
 * content entry reference, but this function reconstructs as much as possible.
 * @param content a Nacelle v2 reference to a content entry that originates from Contentful.
 * @returns a mostly-reconstructed Contentful entry.
 */
export function reconstructContentfulEntry(
  content: NacelleContentEntry
): ReconstructedContentfulEntry {
  const { sourceEntryId } = destructureNacelleEntryId(
    content.nacelleEntryId as string
  );
  return {
    fields: content.fields as AnyObject,
    metadata: {
      tags: content.tags ?? []
    },
    sys: {
      id: sourceEntryId,
      type: 'Entry',
      contentType: {
        sys: {
          id: content.type ?? '',
          linkType: 'ContentType',
          type: 'Link'
        }
      }
    }
  };
}
