import Logger from 'src/application/logging/logger';
import { OrderItemInfo, OrderResponseAttributes } from '@spiffy-ai/commerce-api-client';
import { hasPropertyOfType } from 'src/application/models/guards/utils';

const logger = new Logger('isApiOrderResponseAttributes');

// the client SDK generates date-time format types as `Date` but the openapi typescript generator
// does not correctly deserialize date-time values so they are always `string` at runtime instead of
// `Date` objects. These interfaces override the SDK types so that we can validate against the actual
// `string` values. https://github.com/OpenAPITools/openapi-generator/issues/926
export interface ApiOrderItemInfo extends Omit<
  OrderItemInfo,
  'delivered_at' | 'estimated_delivery_at' | 'in_transit_at'
> {
  delivered_at?: string;
  estimated_delivery_at?: string;
  in_transit_at?: string;
}

export interface ApiOrderResponseAttributes extends Omit<
  OrderResponseAttributes,
  'created_at' | 'latest_event_date' | 'line_items'
> {
  created_at: string;
  latest_event_date: string;
  line_items: ApiOrderItemInfo[];
}

const isApiOrderItemInfo = (data: unknown): data is ApiOrderItemInfo => {
  if (data == null || typeof data !== 'object') {
    logger.logError('OrderItemInfo must be an object', undefined, { data });
    return false;
  }

  if (!hasPropertyOfType(data, 'order_item_id', 'string')) {
    logger.logError('OrderItemInfo must have an order_item_id property', undefined, { data });
    return false;
  }

  if (!hasPropertyOfType(data, 'item_title', 'string')) {
    logger.logError('OrderItemInfo must have an item_title property', undefined, { data });
    return false;
  }

  if (!hasPropertyOfType(data, 'item_price', 'number')) {
    logger.logError('OrderItemInfo must have an item_price property', undefined, { data });
    return false;
  }

  if (!hasPropertyOfType(data, 'item_quantity', 'number')) {
    logger.logError('OrderItemInfo must have an item_quantity property', undefined, { data });
    return false;
  }

  if (!hasPropertyOfType(data, 'image', 'string', true)) {
    logger.logError('OrderItemInfo.image must be a string or null', undefined, { data });
    return false;
  }

  if (!hasPropertyOfType(data, 'fulfillment_display_status', 'string', true)) {
    logger.logError(
      'OrderItemInfo.fulfillment_display_status must be a string or null',
      undefined,
      {
        data,
      },
    );
    return false;
  }

  if (!hasPropertyOfType(data, 'tracking_url', 'string', true)) {
    logger.logError('OrderItemInfo.tracking_url must be a string or null', undefined, { data });
    return false;
  }

  if (!hasPropertyOfType(data, 'delivered_at', 'string', true)) {
    logger.logError('OrderItemInfo.delivered_at must be a string or null', undefined, { data });
    return false;
  }

  if (!hasPropertyOfType(data, 'estimated_delivery_at', 'string', true)) {
    logger.logError('OrderItemInfo.estimated_delivery_at must be a string or null', undefined, {
      data,
    });
    return false;
  }

  if (!hasPropertyOfType(data, 'in_transit_at', 'string', true)) {
    logger.logError('OrderItemInfo.in_transit_at must be a string or null', undefined, { data });
    return false;
  }

  return true;
};

export const isApiOrderResponseAttributes = (data: unknown): data is ApiOrderResponseAttributes => {
  if (data == null || typeof data !== 'object') {
    logger.logError('Order response attributes must be an object', undefined, { data });
    return false;
  }

  if (!hasPropertyOfType(data, 'created_at', 'string')) {
    logger.logError(
      'Order response attributes must have a created_at property and have type string',
      undefined,
      {
        data,
      },
    );
    return false;
  }

  if (!hasPropertyOfType(data, 'latest_event_date', 'string')) {
    logger.logError(
      'Order response attributes must have a latest_event_date property and have type string',
      undefined,
      {
        data,
      },
    );
    return false;
  }

  if (
    !hasPropertyOfType(data, 'line_items', 'array') ||
    !data.line_items.every((item: unknown) => isApiOrderItemInfo(item))
  ) {
    logger.logError(
      'Order response attributes must have a line_items property with at least one order item',
      undefined,
      {
        data,
      },
    );
    return false;
  }

  if (!hasPropertyOfType(data, 'order_id', 'string')) {
    logger.logError(
      'Order response attributes must have an order_id property and have type string',
      undefined,
      {
        data,
      },
    );
    return false;
  }

  if (!hasPropertyOfType(data, 'order_number', 'string')) {
    logger.logError(
      'Order response attributes must have an order_number property and have type string',
      undefined,
      {
        data,
      },
    );
    return false;
  }

  return true;
};
