import AddToCartEventHandler, { AddToCartEventOptions } from '../index'
import BaseEventHandler from '../../base'
import { EventCallbackOptions } from '../../base'
import { createLogger, ErrorProperties } from '../../../utils/logger'
import { makeContext, makeSettings } from '../../../__tests__/helpers'
import SdkSettings from '../../../settings'
import { EcRenderConfig } from '../../../enhancedContent'

const logger = createLogger(makeContext(), makeSettings())

describe('AddToCartEventHandler', () => {
  let handlerSpy: jest.SpyInstance<void, [options: EventCallbackOptions, extraProperties?: Record<string, unknown>]>
  let _subject: AddToCartEventHandler

  describe('#event_name', () => {
    test('it is correct', () => {
      _subject = new AddToCartEventHandler(logger)

      expect(_subject.eventName).toBe('add_to_cart')
    })
  })

  describe('#handle', () => {
    let loggerSpy: jest.SpyInstance<
      void,
      [string, (Record<string, unknown> | SdkSettings | EcRenderConfig | undefined)?]
    >

    const options = {
      quantity: 1,
      productIdType: 'test-id-type',
      productId: 'test-id',
    }

    beforeEach(() => {
      handlerSpy = jest.spyOn(BaseEventHandler.prototype, 'handle')
      _subject = new AddToCartEventHandler(logger)
      loggerSpy = jest.spyOn(logger, 'log').mockImplementation()
    })

    afterEach(() => {
      loggerSpy.mockClear()
    })

    test('it calls super with the right params', () => {
      _subject.handle(options)

      expect(handlerSpy).toHaveBeenCalledWith(options, undefined)
    })

    describe('validation', () => {
      const handler = new AddToCartEventHandler(logger)

      const testValidation = (options: AddToCartEventOptions, errorMessage: ErrorProperties['errorMessage']): void => {
        expect(() => handler.handle(options)).toThrow(errorMessage)
        expect(loggerSpy).toHaveBeenCalledTimes(1)
        expect(loggerSpy).toHaveBeenCalledWith('error', {
          errorContext: 'event',
          errorType: 'validation',
          errorMessage,
        })
      }

      describe('currency', () => {
        test('it throws and logs an error for non-alphabetic currency codes', () => {
          testValidation(
            { ...options, price: 10, currency: '840' },
            'Invalid 3-character alphabetic ISO-4217 currency code: 840. See: https://www.iso.org/iso-4217-currency-codes.html.'
          )
        })

        test('it throws and logs an error for currency codes with more than 3 letters', () => {
          testValidation(
            { ...options, price: 10, currency: 'Euro' },
            'Invalid 3-character alphabetic ISO-4217 currency code: Euro. See: https://www.iso.org/iso-4217-currency-codes.html.'
          )
        })

        test('it throws and logs an error for currency codes with less than 3 letters', () => {
          testValidation(
            { ...options, price: 10, currency: 'US' },
            'Invalid 3-character alphabetic ISO-4217 currency code: US. See: https://www.iso.org/iso-4217-currency-codes.html.'
          )
        })

        test('it throws and logs an error for uncapitalized currency codes', () => {
          testValidation(
            { ...options, price: 10, currency: 'usd' },
            'Invalid 3-character alphabetic ISO-4217 currency code: usd. See: https://www.iso.org/iso-4217-currency-codes.html.'
          )
        })

        test('it does not throw or log an error for 3-character alphabetic ISO-4217 currency codes', () => {
          const eventOptions = { ...options, price: 10, currency: 'USD' }
          handler.handle(eventOptions)
          expect(loggerSpy).toHaveBeenCalledTimes(1)
          expect(loggerSpy).toHaveBeenCalledWith(handler.eventName, eventOptions)
        })
      })
    })
  })
})
