/* eslint-disable sonarjs/no-duplicate-string */
import {actions, EventFrom, send, StateFrom} from 'xstate';
import {AppServices} from '../../../shared/GlobalContext';
import {TelemetryConstants} from '../../../shared/telemetry/TelemetryConstants';
import {
  getStartEventData,
  sendStartEvent,
} from '../../../shared/telemetry/TelemetryUtils';
import {qrLoginMachine} from '../../QrLogin/QrLoginMachine';
// @ts-ignore
import {ScanActions} from './scanActions';
import {ScanGuards} from './scanGuards';
import {ScanModel} from './scanModel';
import {ScanServices} from './scanServices';
import {openID4VPMachine} from '../../openID4VP/openID4VPMachine';

const model = ScanModel;
export const ScanEvents = model.events;

export const scanMachine =
  /** @xstate-layout [encoded data, 7120 characters] */
  model.createMachine(
    {
      predictableActionArguments: true,
      preserveActionOrder: true,
      tsTypes: {} as import('./scanMachine.typegen').Typegen0,
      schema: {
        context: model.initialContext,
        events: {} as EventFrom<typeof model>,
      },
      invoke: {
        src: 'monitorConnection',
      },
      id: 'scan',
      initial: 'inactive',
      on: {
        SCREEN_BLUR: {
          actions: 'resetOpenID4VPFlowType',
          target: '#scan.disconnectDevice',
        },
        SCREEN_FOCUS: {
          target: '.checkStorage',
        },
        BLE_ERROR: {
          target: '.handlingBleError',
          actions: ['sendBLEConnectionErrorEvent', 'setBleError'],
        },
        RESET: {
          actions: [
            'removeLoggers',
            'resetFlowType',
            'resetOpenID4VPFlowType',
            'resetSelectedVc',
            'resetIsQrLoginViaDeepLink',
            'resetIsOVPViaDeepLink',
            'resetAuthorizationRequest',
            'resetLinkCode',
          ],
          target: '.checkStorage',
        },
        DISMISS: {
          target: '#scan.reviewing.disconnect',
        },
        SELECT_VC: {
          actions: ['setSelectedVc', 'setFlowType'],
          target: '.checkStorage',
        },
        DISMISS_QUICK_SHARE_BANNER: {
          actions: 'resetShowQuickShareSuccessBanner',
          target: '.inactive',
        },
        QRLOGIN_VIA_DEEP_LINK: {
          actions: [
            'setQrLoginRef',
            'setLinkCodeFromDeepLink',
            'setIsQrLoginViaDeepLink',
          ],
          target: '#scan.checkStorage',
        },
        OVP_VIA_DEEP_LINK: {
          actions: [
            'setAuthRequestFromDeepLink',
            'setIsOVPViaDeepLink',
            'setOpenId4VPFlowType',
          ],
          target: '#scan.checkStorage',
        },
      },
      states: {
        inactive: {
          entry: [
            'removeLoggers',
            'resetFlowType',
            'resetSelectedVc',
            'setOpenId4VPRef',
          ],
        },
        disconnectDevice: {
          invoke: {
            src: 'disconnect',
          },
          on: {
            DISCONNECT: {
              target: '#scan.inactive',
            },
          },
        },
        checkStorage: {
          entry: 'setOpenId4VPRef',
          invoke: {
            src: 'checkStorageAvailability',
            onDone: [
              {
                cond: 'isMinimumStorageRequiredForAuditEntryReached',
                target: 'restrictSharingVc',
              },
              {
                target: 'startPermissionCheck',
              },
            ],
          },
        },
        restrictSharingVc: {},

        startPermissionCheck: {
          on: {
            START_PERMISSION_CHECK: [
              {
                cond: 'isFlowTypeDeepLink',
                target: '#scan.checkFaceAuthConsent',
              },
              {
                cond: 'uptoAndroid11',
                target: '#scan.checkBluetoothPermission',
              },
              {
                cond: 'isIOS',
                target: '#scan.checkBluetoothPermission',
              },
              {
                target: '#scan.checkNearbyDevicesPermission',
              },
            ],
          },
        },

        checkNearbyDevicesPermission: {
          initial: 'checking',
          states: {
            checking: {
              invoke: {
                src: 'checkNearByDevicesPermission',
              },
              on: {
                NEARBY_ENABLED: {
                  target: 'enabled',
                },
                NEARBY_DISABLED: {
                  target: 'requesting',
                },
              },
            },
            requesting: {
              invoke: {
                src: 'requestNearByDevicesPermission',
              },
              on: {
                NEARBY_ENABLED: {
                  target: '#scan.checkBluetoothPermission',
                },
                NEARBY_DISABLED: {
                  target: '#scan.nearByDevicesPermissionDenied',
                },
              },
            },
            enabled: {
              always: {
                target: '#scan.checkBluetoothPermission',
              },
            },
          },
        },

        checkBluetoothPermission: {
          initial: 'checking',
          states: {
            checking: {
              invoke: {
                src: 'checkBluetoothPermission',
              },
              on: {
                BLUETOOTH_PERMISSION_ENABLED: {
                  actions: 'setReadyForBluetoothStateCheck',
                  target: 'enabled',
                },
                BLUETOOTH_PERMISSION_DENIED: {
                  target: '#scan.bluetoothPermissionDenied',
                },
              },
            },
            enabled: {
              always: {
                target: '#scan.checkBluetoothState',
              },
            },
          },
        },

        checkBluetoothState: {
          initial: 'checking',
          states: {
            checking: {
              invoke: {
                src: 'checkBluetoothState',
              },
              on: {
                BLUETOOTH_STATE_ENABLED: {
                  target: 'enabled',
                },
                BLUETOOTH_STATE_DISABLED: [
                  {
                    cond: 'isIOS',
                    target: '#scan.checkBluetoothPermission',
                  },
                  {
                    target: 'requesting',
                  },
                ],
              },
            },
            requesting: {
              invoke: {
                src: 'requestBluetooth',
              },
              on: {
                BLUETOOTH_STATE_ENABLED: {
                  target: 'enabled',
                },
                BLUETOOTH_STATE_DISABLED: {
                  target: '#scan.bluetoothDenied',
                },
              },
            },
            enabled: {
              always: [
                {
                  cond: 'uptoAndroid11',
                  target: '#scan.checkingLocationState',
                },
                {
                  target: '#scan.clearingConnection',
                },
              ],
            },
          },
        },

        recheckBluetoothState: {
          initial: 'checking',
          states: {
            checking: {
              invoke: {
                src: 'checkBluetoothState',
              },
              on: {
                BLUETOOTH_STATE_ENABLED: {
                  target: 'enabled',
                },
                BLUETOOTH_STATE_DISABLED: {
                  target: '#scan.bluetoothDenied',
                },
              },
            },
            enabled: {
              always: [
                {
                  cond: 'uptoAndroid11',
                  target: '#scan.checkingLocationState',
                },
                {
                  target: '#scan.clearingConnection',
                },
              ],
            },
          },
        },

        bluetoothPermissionDenied: {
          on: {
            APP_ACTIVE: '#scan.checkBluetoothState',
            GOTO_SETTINGS: {
              actions: 'openBluetoothSettings',
            },
          },
        },

        bluetoothDenied: {
          on: {
            APP_ACTIVE: '#scan.recheckBluetoothState',
          },
        },

        nearByDevicesPermissionDenied: {
          on: {
            APP_ACTIVE: '#scan.checkNearbyDevicesPermission',
            GOTO_SETTINGS: {
              actions: 'openAppPermission',
            },
          },
        },

        clearingConnection: {
          invoke: {
            src: 'disconnect',
          },
          on: {
            DISCONNECT: {
              target: '#scan.checkFaceAuthConsent',
              internal: false,
            },
          },
          after: {
            DESTROY_TIMEOUT: {
              target: '#scan.checkFaceAuthConsent',
              actions: [],
              internal: false,
            },
          },
        },
        checkFaceAuthConsent: {
          entry: 'getFaceAuthConsent',
          on: {
            STORE_RESPONSE: {
              actions: 'updateShowFaceAuthConsent',
              target: '#scan.checkForDeepLinkFlow',
            },
          },
        },
        checkForDeepLinkFlow: {
          always: [
            {
              cond: 'isQrLoginViaDeepLinking',
              target: '#scan.showQrLogin',
            },
            {
              cond: 'isOVPViaDeepLink',
              actions: ['setOpenId4VPFlowType'],
              target: '#scan.startVPSharing',
            },
            {
              target: '#scan.findingConnection',
            },
          ],
        },
        findingConnection: {
          entry: [
            'removeLoggers',
            'registerLoggers',
            'clearUri',
            'resetFaceCaptureBannerStatus',
          ],
          on: {
            SCAN: [
              {
                target: 'connecting',
                cond: 'isOpenIdQr',
                actions: ['sendVcSharingStartEvent', 'setUri'],
              },
              {
                target: 'showQrLogin',
                cond: 'isQrLogin',
                actions: [
                  'setQrLoginRef',
                  'sendVcSharingStartEvent',
                  'setLinkCode',
                ],
              },
              {
                target: 'startVPSharing',
                cond: 'isOnlineSharing',
                actions: ['setOpenId4VPFlowType', 'setAuthRequestFromDeepLink'],
              },
              {
                target: 'decodeQuickShareData',
                cond: 'isQuickShare',
                actions: 'setQuickShareData',
              },
              {
                target: 'invalid',
              },
            ],
          },
        },
        startVPSharing: {
          entry: [
            'sendVPScanData',
            () =>
              sendStartEvent(
                getStartEventData(TelemetryConstants.FlowType.vpSharing),
              ),
          ],
          invoke: {
            id: 'OpenId4VP',
            src: openID4VPMachine,
            onDone: {},
          },
          on: {
            IN_PROGRESS: {
              target: '.inProgress',
            },
            TIMEOUT: {
              target: '.timeout',
            },
            DISMISS: [
              {
                cond: 'isFlowTypeSimpleShare',
                actions: ['resetIsOVPViaDeepLink', 'resetOpenID4VPFlowType'],
                target: 'checkStorage',
              },
              {
                target: 'checkStorage',
              },
            ],
            SHOW_ERROR: {
              target: '.showError',
            },
            SUCCESS: {
              target: '.success',
            },
          },
          states: {
            success: {},
            showError: {},
            inProgress: {
              on: {
                CANCEL: [
                  {
                    cond: 'isFlowTypeSimpleShare',
                    actions: 'resetOpenID4VPFlowType',
                    target: '#scan.checkStorage',
                  },
                  {
                    target: '#scan.checkStorage',
                  },
                ],
              },
            },
            timeout: {
              on: {
                STAY_IN_PROGRESS: {
                  target: 'inProgress',
                },
                CANCEL: [
                  {
                    cond: 'isFlowTypeSimpleShare',
                    actions: 'resetOpenID4VPFlowType',
                    target: '#scan.checkStorage',
                  },
                  {
                    target: '#scan.checkStorage',
                  },
                ],
                RETRY: [
                  {
                    cond: 'isFlowTypeSimpleShare',
                    actions: 'resetOpenID4VPFlowType',
                    target: '#scan.checkStorage',
                  },
                  {
                    target: '#scan.checkStorage',
                  },
                ],
              },
            },
          },
        },
        decodeQuickShareData: {
          entry: 'loadMetaDataToMemory',
          on: {
            STORE_RESPONSE: {
              target: 'loadVCS',
            },
          },
        },
        loadVCS: {
          entry: 'loadVCDataToMemory',
          on: {
            STORE_RESPONSE: {
              actions: ['refreshVCs', 'setShowQuickShareSuccessBanner'],
              target: '.navigatingToHome',
            },
          },
          initial: 'idle',
          states: {
            idle: {},
            navigatingToHome: {},
          },
        },
        showQrLogin: {
          invoke: {
            id: 'QrLogin',
            src: qrLoginMachine,
            onDone: {
              target: '.storing',
            },
          },
          on: {
            DISMISS: {
              actions: ['resetLinkCode', 'resetIsQrLoginViaDeepLink'],
              target: '#scan.checkFaceAuthConsent',
            },
          },
          initial: 'idle',
          states: {
            idle: {},
            storing: {
              entry: ['storeLoginItem'],
              on: {
                STORE_RESPONSE: [
                  {
                    cond: 'isQrLoginViaDeepLinking',
                    actions: 'storingActivityLog',
                    target: 'navigatingToHome',
                  },
                  {
                    target: 'navigatingToHistory',
                    actions: ['storingActivityLog'],
                  },
                ],
              },
            },
            navigatingToHistory: {},
            navigatingToHome: {},
          },
          entry: [
            'sendScanData',
            () =>
              sendStartEvent(
                getStartEventData(TelemetryConstants.FlowType.qrLogin),
              ),
          ],
          exit: ['resetLinkCode'],
        },
        connecting: {
          invoke: {
            src: 'startConnection',
          },
          initial: 'inProgress',
          after: {
            CONNECTION_TIMEOUT: {
              target: '.timeout',
              internal: true,
            },
          },
          states: {
            inProgress: {
              on: {
                CANCEL: {
                  target: '#scan.reviewing.cancelling',
                },
              },
            },
            timeout: {
              on: {
                STAY_IN_PROGRESS: {
                  target: 'inProgress',
                },
                CANCEL: {
                  target: '#scan.reviewing.cancelling',
                },
                RETRY: {
                  target: '#scan.reviewing.cancelling',
                },
              },
            },
          },
          on: {
            CONNECTED: {
              target: 'reviewing',
              actions: ['setSenderInfo', 'setReceiverInfo'],
            },
          },
        },
        reviewing: {
          initial: 'idle',
          entry: [send('CHECK_FLOW_TYPE')],
          on: {
            CHECK_FLOW_TYPE: [
              {
                cond: 'isFlowTypeSimpleShare',
                target: '.selectingVc',
              },
              {
                cond: 'isFlowTypeMiniViewShare',
                target: '.sendingVc',
                actions: 'setShareLogTypeUnverified',
              },
              {
                cond: 'isFlowTypeMiniViewShareWithSelfie',
                target: '.checkFaceAuthConsentForMiniView',
              },
            ],
          },
          states: {
            idle: {},
            selectingVc: {
              on: {
                DISCONNECT: {
                  target: '#scan.disconnected',
                },
                SELECT_VC: {
                  actions: ['setSelectedVc', 'setFlowType'],
                },
                VERIFY_AND_ACCEPT_REQUEST: [
                  {
                    cond: 'showFaceAuthConsentScreen',
                    target: 'faceVerificationConsent',
                  },
                  {
                    target: 'verifyingIdentity',
                  },
                ],
                ACCEPT_REQUEST: {
                  target: 'sendingVc',
                  actions: [
                    'setShareLogTypeUnverified',
                    'resetFaceCaptureBannerStatus',
                  ],
                },
                CANCEL: {
                  target: 'cancelling',
                  actions: 'sendVCShareFlowCancelEndEvent',
                },
              },
            },
            cancelling: {
              always: {
                target: '#scan.clearingConnection',
              },
            },
            sendingVc: {
              invoke: {
                src: 'sendVc',
              },
              after: {
                SHARING_TIMEOUT: {
                  target: '.timeout',
                  internal: true,
                },
              },
              initial: 'inProgress',
              states: {
                inProgress: {
                  on: {
                    CANCEL: {
                      target: '#scan.reviewing.cancelling',
                      actions: ['sendVCShareFlowCancelEndEvent'],
                    },
                    CLOSE_BANNER: {
                      actions: ['resetFaceCaptureBannerStatus'],
                    },
                  },
                },
                timeout: {
                  on: {
                    STAY_IN_PROGRESS: {
                      target: 'inProgress',
                    },
                    CANCEL: {
                      target: '#scan.reviewing.cancelling',
                      actions: ['sendVCShareFlowTimeoutEndEvent'],
                    },
                    RETRY: {
                      target: '#scan.reviewing.cancelling',
                      actions: ['sendVCShareFlowTimeoutEndEvent'],
                    },
                  },
                },
                sent: {
                  description:
                    'VC data has been shared and the receiver should now be viewing it',
                  on: {
                    CANCEL: {
                      target: '#scan.reviewing.cancelling',
                    },
                  },
                },
              },
              on: {
                DISCONNECT: {
                  target: '#scan.disconnected',
                },
                VC_SENT: {
                  target: '.sent',
                },
                VC_ACCEPTED: {
                  target: '#scan.reviewing.accepted',
                },
                VC_REJECTED: {
                  target: '#scan.reviewing.rejected',
                },
                CANCEL: {
                  target: '#scan.reviewing.cancelling',
                },
              },
            },
            accepted: {
              entry: ['logShared', 'sendVcShareSuccessEvent'],
              on: {
                DISMISS: {
                  target: 'disconnect',
                },
                GOTO_HISTORY: {
                  target: 'navigateToHistory',
                },
              },
            },
            rejected: {
              on: {
                RETRY: {
                  target: '#scan.clearingConnection',
                },
              },
            },
            disconnect: {
              entry: [
                'resetFlowType',
                'resetSelectedVc',
                'resetShowQuickShareSuccessBanner',
              ],
              invoke: {
                src: 'disconnect',
              },
            },
            navigateToHistory: {
              entry: ['resetFlowType', 'resetSelectedVc'],
              always: '#scan.disconnected',
            },
            checkFaceAuthConsentForMiniView: {
              always: [
                {
                  cond: 'showFaceAuthConsentScreen',
                  target: 'faceVerificationConsent',
                },
                {
                  target: 'verifyingIdentity',
                },
              ],
            },
            faceVerificationConsent: {
              on: {
                FACE_VERIFICATION_CONSENT: {
                  actions: [
                    'setShowFaceAuthConsent',
                    'storeShowFaceAuthConsent',
                  ],
                  target: 'verifyingIdentity',
                },
                DISMISS: [
                  {
                    cond: 'isFlowTypeMiniViewShareWithSelfie',
                    target: '#scan.checkFaceAuthConsent',
                  },
                  {
                    target: '#scan.reviewing.selectingVc',
                  },
                ],
              },
            },
            verifyingIdentity: {
              on: {
                FACE_VALID: {
                  target: 'sendingVc',
                  actions: [
                    'setShareLogTypeVerified',
                    'updateFaceCaptureBannerStatus',
                  ],
                },
                FACE_INVALID: {
                  target: 'invalidIdentity',
                  actions: 'logFailedVerification',
                },
                CANCEL: [
                  {
                    cond: 'isFlowTypeSimpleShare',
                    target: 'selectingVc',
                  },
                  {
                    target: 'cancelling',
                  },
                ],
              },
            },

            invalidIdentity: {
              on: {
                DISMISS: [
                  {
                    cond: 'isFlowTypeSimpleShare',
                    actions: ['resetBleError'],
                    target: 'selectingVc',
                  },
                  {
                    actions: ['resetBleError'],
                    target: 'cancelling',
                  },
                ],
                RETRY_VERIFICATION: {
                  target: 'verifyingIdentity',
                },
              },
            },
          },
        },
        disconnected: {
          on: {
            RETRY: {
              target: '#scan.reviewing.cancelling',
            },
            DISMISS: {
              target: '#scan.reviewing.disconnect',
            },
          },
        },
        handlingBleError: {
          on: {
            RETRY: {
              target: '#scan.reviewing.cancelling',
            },
            DISMISS: {
              target: '#scan.clearingConnection',
            },
          },
        },
        invalid: {
          on: {
            DISMISS: {
              target: '#scan.clearingConnection',
            },
          },
        },
        checkingLocationState: {
          initial: 'checkLocationService',
          states: {
            checkLocationService: {
              invoke: {
                src: 'checkLocationStatus',
              },
              on: {
                LOCATION_ENABLED: {
                  target: 'checkingPermissionStatus',
                },
                LOCATION_DISABLED: {
                  target: 'LocationPermissionRationale',
                },
              },
            },
            LocationPermissionRationale: {
              on: {
                APP_ACTIVE: {
                  target: 'checkLocationService',
                },
                ALLOWED: {
                  actions: 'enableLocation',
                },
                DENIED: {
                  target: 'disabled',
                },
              },
            },
            checkingPermissionStatus: {
              invoke: {
                src: 'checkLocationPermission',
              },
              on: {
                LOCATION_ENABLED: {
                  target: '#scan.clearingConnection',
                },
                LOCATION_DISABLED: {
                  target: 'requestToEnableLocation',
                },
              },
            },
            requestToEnableLocation: {
              invoke: {
                src: 'requestToEnableLocationPermission',
              },
              on: {
                LOCATION_ENABLED: {
                  target: '#scan.clearingConnection',
                },
                LOCATION_DISABLED: {
                  target: 'denied',
                },
              },
            },
            denied: {
              on: {
                LOCATION_REQUEST: {
                  actions: 'openAppPermission',
                },
              },
            },
            disabled: {
              on: {
                LOCATION_REQUEST: {
                  target: 'checkLocationService',
                  actions: 'enableLocation',
                },
              },
            },
          },
        },
      },
    },
    {
      actions: ScanActions(model),
      services: ScanServices(model),
      guards: ScanGuards(),
      delays: {
        DESTROY_TIMEOUT: 500,
        CONNECTION_TIMEOUT: 5 * 1000,
        SHARING_TIMEOUT: 15 * 1000,
      },
    },
  );

type State = StateFrom<typeof scanMachine>;

export function createScanMachine(serviceRefs: AppServices) {
  return scanMachine.withContext({
    ...scanMachine.context,
    serviceRefs,
  });
}
