import type { LocaleConfig, SupportedLanguages } from '~types/locales'
import type {
  DocumentTypes,
  DocumentTypeConfig,
  StepConfig,
  StepTypes,
} from '~types/steps'
import type { ServerRegions, SdkOptions } from '~types/sdk'
import type { UICustomizationOptions } from '~types/ui-customisation-options'
import customUIConfig from './custom-ui-config.json'
import testDarkCobrandLogo from './assets/onfido-logo.svg'
import testLightCobrandLogo from './assets/onfido-logo-light.svg'

type StringifiedBoolean = 'true' | 'false'
type DecoupleResponseOptions = 'success' | 'error' | 'onfido'

export type QueryParams = {
  countryCode?: StringifiedBoolean
  disableAnalytics?: StringifiedBoolean
  forceCrossDevice?: StringifiedBoolean
  hideOnfidoLogo?: StringifiedBoolean
  language?: 'customTranslations' | SupportedLanguages
  customWelcomeScreenCopy?: StringifiedBoolean
  link_id?: string
  liveness?: StringifiedBoolean
  multiDocWithInvalidPresetCountry?: StringifiedBoolean
  multiDocWithPresetCountry?: StringifiedBoolean
  multiDocWithBooleanValues?: StringifiedBoolean
  noCompleteStep?: StringifiedBoolean
  oneDoc?: DocumentTypes
  oneDocWithCountrySelection?: StringifiedBoolean
  oneDocWithPresetCountry?: StringifiedBoolean
  poa?: StringifiedBoolean
  region?: string
  shouldCloseOnOverlayClick?: StringifiedBoolean
  showCobrand?: StringifiedBoolean
  showLogoCobrand?: StringifiedBoolean
  showUserConsent?: StringifiedBoolean
  showAuth?: StringifiedBoolean
  smsNumber?: StringifiedBoolean
  snapshotInterval?: string
  uploadFallback?: StringifiedBoolean
  useHistory?: StringifiedBoolean
  useLiveDocumentCapture?: StringifiedBoolean
  useMemoryHistory?: StringifiedBoolean
  useModal?: StringifiedBoolean
  useMultipleSelfieCapture?: StringifiedBoolean
  useUploader?: StringifiedBoolean
  useWebcam?: StringifiedBoolean
  customisedUI?: StringifiedBoolean
  useCustomizedApiRequests?: StringifiedBoolean
  decoupleResponse?: DecoupleResponseOptions
  photoCaptureFallback?: StringifiedBoolean
}

export type CheckData = {
  applicantId?: string
  sdkFlowCompleted: boolean
}

export type UIConfigs = {
  darkBackground: boolean
  iframeWidth: string
  iframeHeight: string
  tearDown: boolean
}

const SAMPLE_LOCALE: LocaleConfig = {
  locale: 'en',
  phrases: { 'welcome.title': 'My custom title' },
  mobilePhrases: {
    'capture.driving_licence.back.instructions': 'Custom instructions',
  },
}

export const queryParamToValueString = window.location.search
  .slice(1)
  .split('&')
  .reduce((acc: QueryParams, cur: string) => {
    const [key, value] = cur.split('=')
    return { ...acc, [key]: value }
  }, {})

const getPreselectedDocumentTypes = (): Partial<
  Record<DocumentTypes, DocumentTypeConfig>
> => {
  const preselectedDocumentType = queryParamToValueString.oneDoc

  if (preselectedDocumentType) {
    return {
      [preselectedDocumentType]: true,
    }
  }

  if (queryParamToValueString.oneDocWithCountrySelection === 'true') {
    return {
      driving_licence: true,
    }
  }

  if (queryParamToValueString.oneDocWithPresetCountry === 'true') {
    return {
      driving_licence: {
        country: 'ESP',
      },
    }
  }

  if (queryParamToValueString.multiDocWithPresetCountry === 'true') {
    return {
      driving_licence: {
        country: 'ESP',
      },
      national_identity_card: {
        country: 'MYS',
      },
      residence_permit: {
        country: null,
      },
    }
  }

  if (queryParamToValueString.multiDocWithInvalidPresetCountry === 'true') {
    return {
      driving_licence: {
        country: 'ES',
      },
      national_identity_card: {
        country: 'XYZ',
      },
    }
  }

  if (queryParamToValueString.multiDocWithBooleanValues === 'true') {
    return {
      driving_licence: true,
      national_identity_card: true,
    }
  }

  return {}
}

export const getInitSdkOptions = (): SdkOptions => {
  const linkId = queryParamToValueString.link_id as string

  if (linkId) {
    return {
      mobileFlow: true,
      roomId: linkId.substring(2),
    }
  }

  const language =
    queryParamToValueString.language === 'customTranslations'
      ? SAMPLE_LOCALE
      : queryParamToValueString.language

  const steps: Array<StepConfig> = []

  if (queryParamToValueString.customWelcomeScreenCopy === 'true') {
    steps.push({
      type: 'welcome',
      options: {
        title: 'Open your new bank account',
        descriptions: [
          'To open a bank account, we will need to verify your identity.',
          'It will only take a couple of minutes.',
        ],
        nextButton: 'Verify Identity',
      },
    })
  } else {
    steps.push({ type: 'welcome' })
  }

  if (queryParamToValueString.showAuth === 'true') {
    steps.push({ type: 'auth', options: { retries: 10 } })
  }

  if (queryParamToValueString.showUserConsent === 'true') {
    steps.push({ type: 'userConsent' })
  }

  if (queryParamToValueString.poa === 'true') {
    steps.push({ type: 'poa' })
  }

  steps.push({
    type: 'document',
    options: {
      useLiveDocumentCapture:
        queryParamToValueString.useLiveDocumentCapture === 'true',
      uploadFallback: queryParamToValueString.uploadFallback !== 'false',
      useWebcam: queryParamToValueString.useWebcam === 'true',
      documentTypes: getPreselectedDocumentTypes(),
      showCountrySelection:
        queryParamToValueString.oneDocWithCountrySelection === 'true',
      forceCrossDevice: queryParamToValueString.forceCrossDevice === 'true',
    },
  })

  steps.push({
    type: 'face',
    options: {
      requestedVariant:
        queryParamToValueString.liveness === 'true' ? 'video' : 'standard',
      useUploader: queryParamToValueString.useUploader === 'true',
      uploadFallback: queryParamToValueString.uploadFallback !== 'false',
      useMultipleSelfieCapture:
        queryParamToValueString.useMultipleSelfieCapture !== 'false',
      photoCaptureFallback:
        queryParamToValueString.photoCaptureFallback !== 'false',
    },
  })

  if (queryParamToValueString.noCompleteStep !== 'true') {
    steps.push({ type: 'complete' })
  }

  const smsNumberCountryCode = queryParamToValueString.countryCode
    ? { smsNumberCountryCode: queryParamToValueString.countryCode }
    : {}

  const hideOnfidoLogo = queryParamToValueString.hideOnfidoLogo === 'true'
  const cobrand =
    queryParamToValueString.showCobrand === 'true'
      ? { text: 'Planet Express, Incorporated' }
      : undefined
  const logoCobrand =
    queryParamToValueString.showLogoCobrand === 'true'
      ? { lightLogoSrc: testLightCobrandLogo, darkLogoSrc: testDarkCobrandLogo }
      : undefined
  const useCustomizedApiRequests =
    queryParamToValueString.useCustomizedApiRequests === 'true'
  let decoupleCallbacks = {}
  if (queryParamToValueString.decoupleResponse === 'success') {
    const successResponse = Promise.resolve({
      onfidoSuccessResponse: {
        id: '123-456-789',
      },
    })
    decoupleCallbacks = {
      onSubmitDocument: () => successResponse,
      onSubmitSelfie: () => successResponse,
      onSubmitVideo: () => successResponse,
    }
  } else if (queryParamToValueString.decoupleResponse === 'error') {
    const errorResponse = {
      status: 422,
      response: JSON.stringify({
        error: {
          message: 'There was a validation error on this request',
          type: 'validation_error',
          fields: { detect_glare: ['glare found in image'] },
        },
      }),
    }
    decoupleCallbacks = {
      onSubmitDocument: () => Promise.reject(errorResponse),
      onSubmitSelfie: () => Promise.reject(errorResponse),
      onSubmitVideo: () => Promise.reject(errorResponse),
    }
  } else if (queryParamToValueString.decoupleResponse === 'onfido') {
    const response = Promise.resolve({ continueWithOnfidoSubmission: true })
    decoupleCallbacks = {
      onSubmitDocument: () => response,
      onSubmitSelfie: () => response,
      onSubmitVideo: () => response,
    }
  }

  const customUI =
    queryParamToValueString.customisedUI === 'true' ? customUIConfig : undefined

  return {
    useModal: queryParamToValueString.useModal === 'true',
    shouldCloseOnOverlayClick:
      queryParamToValueString.shouldCloseOnOverlayClick !== 'true',
    language,
    disableAnalytics: queryParamToValueString.disableAnalytics === 'true',
    useMemoryHistory: queryParamToValueString.useMemoryHistory === 'true',
    steps,
    mobileFlow: false,
    userDetails: {
      smsNumber: queryParamToValueString.smsNumber,
    },
    enterpriseFeatures: {
      hideOnfidoLogo,
      cobrand,
      logoCobrand,
      useCustomizedApiRequests,
      ...decoupleCallbacks,
    },
    customUI: customUI as UICustomizationOptions,
    ...smsNumberCountryCode,
  }
}

export const commonSteps: Record<string, Array<StepTypes | StepConfig>> = {
  standard: [],

  liveness: [
    'welcome',
    'document',
    {
      type: 'face',
      options: { requestedVariant: 'video' },
    },
    'complete',
  ],

  poa: ['welcome', 'poa', 'complete'],

  'no welcome': ['document', 'face', 'complete'],

  'no complete': ['welcome', 'document', 'face'],

  'upload fallback': [
    'welcome',
    {
      type: 'document',
      options: {
        useWebcam: false,
      },
    },
    {
      type: 'face',
      options: {
        uploadFallback: true,
      },
    },
    'complete',
  ],
  'document autocapture (BETA)': [
    'welcome',
    {
      type: 'document',
      options: {
        useWebcam: true,
      },
    },
    'face',
    'complete',
  ],
  'document live capture (BETA)': [
    'welcome',
    {
      type: 'document',
      options: {
        useLiveDocumentCapture: true,
      },
    },
    'face',
    'complete',
  ],
  'force cross device (docs)': [
    'welcome',
    {
      type: 'document',
      options: {
        forceCrossDevice: true,
      },
    },
    'face',
    'complete',
  ],
  'no upload fallback': [
    'welcome',
    {
      type: 'document',
      options: {
        useWebcam: false,
      },
    },
    {
      type: 'face',
      options: {
        uploadFallback: false,
      },
    },
    'complete',
  ],
  'no snapshot': [
    'welcome',
    'document',
    {
      type: 'face',
      options: {
        useMultipleSelfieCapture: false,
      },
    },
    'complete',
  ],
}

export const commonLanguages: Record<
  string,
  SupportedLanguages | LocaleConfig
> = {
  en: 'en',
  es: 'es',
  de: 'de',
  fr: 'fr',
  custom: {
    phrases: { 'welcome.title': 'My custom title' },
    mobilePhrases: {
      'capture.driving_licence.back.instructions': 'Custom instructions',
    },
  },
}

export const commonRegions: ServerRegions[] = ['EU', 'US', 'CA']

export const getTokenFactoryUrl = (region: ServerRegions): string => {
  if (region === 'US' && process.env.US_JWT_FACTORY) {
    return process.env.US_JWT_FACTORY
  }

  if (region === 'CA' && process.env.CA_JWT_FACTORY) {
    return process.env.CA_JWT_FACTORY
  }

  if (region === 'EU' && process.env.JWT_FACTORY) {
    return process.env.JWT_FACTORY
  }

  throw new Error('No JWT_FACTORY env provided')
}

export const getToken = (
  hasPreview: boolean,
  url: string,
  eventEmitter: MessagePort | undefined,
  onSuccess: (message: string) => void
): void => {
  const request = new XMLHttpRequest()
  request.open('GET', url, true)
  request.setRequestHeader(
    'Authorization',
    `BASIC ${process.env.SDK_TOKEN_FACTORY_SECRET}`
  )
  request.onload = function () {
    if (request.status >= 200 && request.status < 400) {
      const data = JSON.parse(request.responseText)
      if (hasPreview && eventEmitter) {
        eventEmitter.postMessage({
          type: 'UPDATE_CHECK_DATA',
          payload: {
            applicantId: data.applicant_id,
          },
        })
      }
      onSuccess(data.message)
    }
  }
  request.send()
}
