import {
  Base as BaseModel,
} from '@airtable/blocks/models';

import { AtLeastOne } from '../../types/utilTypes';
import { ShopifyObjectType } from '../shopify';
import {
  SHOPIFY_OBJECT_FAMILY,
  ShopifyObjectFamilyToTypes,
  ShopifyObjectTypeToFamily
} from '../shopify/shopifyObjectFamilies';

import {
  AirtableModelAttributes,
  SerializedModelProperties,
} from './AirtableModel';
import {
  SerializedAirtableTable
} from './AirtableTable';

/**
 * Default max records allowed in a base for the Pro plan.
 */
export const DEFAULT_RECORD_MAX = 50000;

export function getAirtableBaseUrl(airtableBaseId: string):string {
  return `https://airtable.com/${airtableBaseId}`;
}

export const DefaultDesyncOrder:readonly SHOPIFY_OBJECT_FAMILY[] = [
  SHOPIFY_OBJECT_FAMILY.ORDERS,
  SHOPIFY_OBJECT_FAMILY.PRODUCTS_AND_INVENTORY,
  SHOPIFY_OBJECT_FAMILY.MISC,
] as const;

export interface BaseSyncConfig {
  shopify_object_types: ShopifyObjectType[];

  /**
   * The order in which we start looking for families to desync. desyncFloor will still be respected, of course.
   */
  desync_order: SHOPIFY_OBJECT_FAMILY[];
  shopify_object_families: AtLeastOne<{
    [type in SHOPIFY_OBJECT_FAMILY]: {

      /**
       * The number of records we won't go below when desyncing. This must be smaller than initialSyncCeiling.
       * As a general rule, the sum of all desyncFloors should be <= record_max
       */
      desyncFloor: number;

      /**
       * The max number of entities we'll sync. This value is used in the initial sync to Airtable. The
       * sum of all initialSyncCeilings should equal record_max. Note that this is an *initial* sync ceiling.
       * The records for a family can go beyond this value given the number of entities in other families.
       * We try to hit record_max as much as possible.
       */
       initialSyncCeiling: number;
    }
  }>;
  record_max: number;
}

const SerializedBaseProperties = [...SerializedModelProperties, 'name'] as const;
type BaseProperties = typeof SerializedBaseProperties[number];

export type SerializedAirtableBase = AirtableModelAttributes<BaseModel, BaseProperties>;

/**
 * When a table is created for each of the Shopify Object types, this AirtableTableLink object captures the current information
 * and should store it onto the base. This allows for tables to potentially be renamed and for the system to still be resilient against
 * these changes.
 */
export type AirtableTableLinks = Partial<{
  [type in ShopifyObjectType]: {
    id: string;
    name: string;
  }
}>;

export function serializeBase(airtableTable: BaseModel): SerializedAirtableBase {
  return SerializedBaseProperties.reduce((accum:any, propertyName:BaseProperties) => {
    accum[propertyName] = airtableTable[propertyName];

    return accum;
  }, {} as SerializedAirtableTable);
}

export function getParentMostSyncedType(shopifyObjectType: ShopifyObjectType, syncConfig: BaseSyncConfig): ShopifyObjectType | null{
  const { shopify_object_types } = syncConfig;

  if (!shopify_object_types.includes(shopifyObjectType)) {
    return null;
  }

  const shopifyObjectFamily = ShopifyObjectTypeToFamily[shopifyObjectType];
  const objectTypesInFamily = ShopifyObjectFamilyToTypes[shopifyObjectFamily] as Readonly<ShopifyObjectType[]>;

  return objectTypesInFamily.find(objectTypeInFamily => shopify_object_types.find(syncedType => syncedType === objectTypeInFamily))!;
}