import { FieldType, } from '@airtable/blocks/models';
import ono from '@jsdevtools/ono';
import { isEqual, keys, omit } from 'lodash';
import { isPresent } from '../../util';
import { SerializedModelProperties, } from './AirtableModel';
const SerializedRecordProperties = [...SerializedModelProperties,
    // 'url', not present in Record returned by REST API and not necessary - can be generated via table id and record id
    // 'createdTime' not present in Record returned by REST API
];
/**
 * Reduces the cell value contained in the Block API Record model to the cell value that the REST API will provide.
 * @param unknownCellValue
 */
function getRestApiFieldValue(unknownCellValue, fieldType) {
    switch (fieldType) {
        /**
         * In these cases, the cell value present in the Block Record has an equivalent type to the value returned by the REST API.
         */
        case FieldType.BUTTON:
        case FieldType.RATING:
        case FieldType.RICH_TEXT:
        case FieldType.DURATION:
        case FieldType.LAST_MODIFIED_TIME:
        case FieldType.BARCODE:
        case FieldType.AUTO_NUMBER:
        case FieldType.PHONE_NUMBER:
        case FieldType.MULTIPLE_ATTACHMENTS:
        case FieldType.CHECKBOX:
        case FieldType.FORMULA:
        case FieldType.CREATED_TIME:
        case FieldType.ROLLUP:
        case FieldType.COUNT:
        case FieldType.DATE:
        case FieldType.DATE_TIME:
        case FieldType.PERCENT:
        case FieldType.CURRENCY:
        case FieldType.NUMBER:
        case FieldType.EMAIL:
        case FieldType.URL:
        case FieldType.MULTILINE_TEXT:
        case FieldType.SINGLE_LINE_TEXT: {
            const returnAsIsCellValue = unknownCellValue;
            return returnAsIsCellValue;
        }
        case FieldType.SINGLE_SELECT: {
            const singleSelectCellValue = unknownCellValue;
            return singleSelectCellValue?.name ?? ABSENT_AIRTABLE_FIELD_VALUE;
        }
        case FieldType.MULTIPLE_SELECTS: {
            const multipleSelectsCellValue = unknownCellValue;
            return multipleSelectsCellValue?.map(cv => cv.name) ?? [];
        }
        case FieldType.MULTIPLE_RECORD_LINKS: {
            const multipleRecordLinksCellValue = unknownCellValue;
            return multipleRecordLinksCellValue?.map(cv => cv.id) ?? [];
        }
        case FieldType.MULTIPLE_LOOKUP_VALUES: {
            const lookupValuesCellValue = unknownCellValue;
            return lookupValuesCellValue?.map(cv => cv.value) ?? [];
        }
        case FieldType.MULTIPLE_COLLABORATORS: {
            const multipleCollaboratorsCellValue = unknownCellValue;
            return multipleCollaboratorsCellValue?.map(cv => omit(cv, 'profilePicUrl')) ?? [];
        }
        case FieldType.SINGLE_COLLABORATOR:
        case FieldType.CREATED_BY:
        case FieldType.LAST_MODIFIED_BY: {
            const singleCollaboratorCellValue = unknownCellValue;
            return omit(singleCollaboratorCellValue, 'profilePicUrl');
        }
    }
}
export const ABSENT_AIRTABLE_FIELD_VALUE = null;
export function getAirtableRecordFieldLinks(airtableTableFieldLinks) {
    return keys(airtableTableFieldLinks)
        .reduce((accum, key) => {
        const shopifyObjectKey = key;
        const airtableTableFieldLink = airtableTableFieldLinks[shopifyObjectKey];
        /**
         * We should only be syncing when we're not missing any fields so we can assume that `id` will exist on the
         * table.airtable_field_links
         */
        accum[shopifyObjectKey] = airtableTableFieldLink.id;
        return accum;
    }, {});
}
export function serializeRecord(airtableRecordModel, airtableTable) {
    const fields = airtableTable.fields.reduce((accum, field) => {
        const { id, name, } = field;
        /**
         * Very important to fall back to null, since the REST API will simply not include fields that don't have values
         * (resulting in an undefined value when the value is accessed), while empty cells access via the Block API will return null.
         * We're going with `null` as the empty value to be consistent across the board. This way when checking for property differences
         * against empty values we won't mark them as different (`null` vs `undefined`) when they're practically the same.
         */
        const restApiFieldValue = getRestApiFieldValue(airtableRecordModel.getCellValue(field.id), field.type) ?? ABSENT_AIRTABLE_FIELD_VALUE;
        accum[id] = {
            name,
            value: restApiFieldValue
        };
        return accum;
    }, {});
    return {
        id: airtableRecordModel.id,
        fields,
    };
}
/**
 * Returns the differences between two records
 * @returns
 */
export function getSerializedRecordsDelta({ oldRecord, newRecord, shopifyObjectType, airtableFieldLinks, }) {
    const syncableShopifyObjectKeys = Object.keys(airtableFieldLinks)
        .filter((key) => isPresent(airtableFieldLinks[key]?.id));
    return syncableShopifyObjectKeys
        .map((key) => {
        try {
            const fieldLink = airtableFieldLinks[key];
            const fieldId = fieldLink.id;
            const oldValue = oldRecord.fields[fieldId].value;
            const newFieldConfig = newRecord.fields[fieldId];
            const newValue = newFieldConfig.value;
            const isDifferent = getAreValuesDifferent({
                value1: oldValue,
                value2: newValue,
            });
            return isDifferent ? {
                shopifyObjectKey: key,
                fieldLink,
                fieldName: newFieldConfig.name,
                oldValue,
                newValue,
            } : null;
        }
        catch (err) {
            const error = ono(err, {
                record1: oldRecord,
                record2: newRecord,
                airtableFieldLinks,
                syncableShopifyObjectKey: key
            });
            throw error;
        }
    })
        .filter(isPresent);
}
/**
 * @param param0
 * @returns
 */
function getAreValuesDifferent({ value1, value2, }) {
    value1 = Array.isArray(value1) ?
        (value1.length ?
            value1 :
            null) :
        value1 ?? null;
    value2 = Array.isArray(value2) ?
        (value2.length ?
            value2 :
            null) :
        value2 ?? null;
    return !isEqual(value1 ?? null, value2 ?? null);
}
//# sourceMappingURL=AirtableRecord.js.map