export interface livenessResult {
  capture_liveness: { probability: number; score: number };
  face_liveness: { probability: number };
}

export interface livenessErrorResult {
  error: string;
  error_code: string;
}
export interface BodyPart {
  /**
   * bodypart name
   */
  bodyPart: string;
  /**
   * base64 data
   */
  data: string;
  img?: string;
  status?: string;
  justification?: string;
  nfiq?: number;
  livenessBlob?: string;
  livenessResult?: livenessResult | livenessErrorResult;
}
export enum Props {
  EXTENSION_NAME = 'extension_name',
  COLLECTOR_SELECT = 'collector_select',
  VIDEO_DIMENSIONS = 'video_dimensions',
  ENABLE_MINUTIAE = 'enable_minutiae',
  WEIGHTS_PATH = 'weights_path',
  LIVENESS_ENABLE = 'liveness_enable',
  IMPORT_LOTTIE = 'import_lottie',
  HIDE_TABS = 'hide_tabs',
  IMPORT_EXTENSION_SCRIPT = 'import_extension_script',
  EXTENSION_URL_SCRIPT = 'extension_url_script',
  EVALUATE_PHOTO = 'evaluate_photo',
  SHOW_CAPTURE_BUTTON = 'show_capture_button',
  SHOW_UNCONFORMITIES = 'show_unconformities',
  VIDEO_OVERLAY = 'video_overlay',
  VIDEO_OVERLAY_TRANSPARENCY= 'video_overlay_transparency',
  SHOW_CONFIG_BUTTON = 'show_config_button',
  SHOW_AUTO_CAPTURE_BUTTON = 'show_auto_capture_button',
  SHOW_CAMERA_BUTTON = 'show_camera_button',
  LANGUAGE = 'language',
  SHOW_JUSTIFICATION_FIELD = 'show_justification_field',
  MIN_EYE_TO_EYE_DIST = 'min_eye_to_eye_dist',
  SHOW_WATERMARK = 'show_watermark',
  FACE_DETECTION_SENSITIVITY = 'face_detection_sensitivity'
}

export const enum BodyPartNames {
  LEFT_HAND_PINKY = 'LEFT_HAND_PINKY',
  LEFT_HAND_RING = 'LEFT_HAND_RING',
  LEFT_HAND_MIDDLE = 'LEFT_HAND_MIDDLE',
  LEFT_HAND_INDEX = 'LEFT_HAND_INDEX',
  LEFT_HAND_THUMB = 'LEFT_HAND_THUMB',
  RIGHT_HAND_THUMB = 'RIGHT_HAND_THUMB',
  RIGHT_HAND_INDEX = 'RIGHT_HAND_INDEX',
  RIGHT_HAND_MIDDLE = 'RIGHT_HAND_MIDDLE',
  RIGHT_HAND_RING = 'RIGHT_HAND_RING',
  RIGHT_HAND_PINKY = 'RIGHT_HAND_PINKY',
  RIGHT_HAND = 'RIGHT_HAND',
  LEFT_HAND = 'LEFT_HAND',
}

export const enum requestResultEnum {
  OK = 'OK',
  TEMPLATE_EXTRACTION_ERROR = 'TEMPLATE_EXTRACTION_ERROR',
  UNKNOWN_TEMPLATE_EXTRACTION_ERROR = 'UNKNOWN_TEMPLATE_EXTRACTION_ERROR',
  LOW_LIVENESS_SCORE = 'LOW_LIVENESS_SCORE',
  LIVENESS_DETECTION_FAILURE = 'LIVENESS_DETECTION_FAILURE',
  UNKNOWN_LIVENESS_ERROR = 'UNKNOWN_LIVENESS_ERROR',
  UNABLE_TO_COMMUNICATE_WITH_LIVENESS_SERVICE = 'UNABLE_TO_COMMUNICATE_WITH_LIVENESS_SERVICE',
  UNABLE_TO_COMMUNICATE_WITH_TEMPLATE_EXTRACTION_SERVICE = 'UNABLE_TO_COMMUNICATE_WITH_TEMPLATE_EXTRACTION_SERVICE',
  LIVENESS_EVALUATION_ERROR = 'LIVENESS_EVALUATION_ERROR',
}

export type FingerIndex = 0 | 1 | 2 | 4 | 6 | 3 | 5 | 7 | 8 | 9 | 10 | 11;
export type FingerName = keyof typeof BodyPartNames;

export interface EventResult {
  'export-face': BodyPart;
  'export-document': BodyPart;
}
export type BryWebCollectorComponentEvent<K> = CustomEvent<K>;

// Once the web component fires events form itself instead of from the window, we can uncomment this
// export type BryWebCollectorComponentEventMap = HTMLElementEventMap &
//   {
//     [P in keyof EventResult]: BryWebCollectorComponentEvent<EventResult[P]>;
//   };

export type exportFace = BryWebCollectorComponentEvent<BodyPart>;
export type exportDocument = BryWebCollectorComponentEvent<BodyPart>;
export type faceUnconformitiesValidated = BryWebCollectorComponentEvent<{
  bodyParts: BodyPart[];
  errorCode?: string;
  icaoWarnings?: string[];
  status: requestResultEnum;
}>;
export type documentUnconformitiesValidated = BryWebCollectorComponentEvent<{
  bodyParts: BodyPart[];
  errorCode?: string;
  status: requestResultEnum;
}>;
export type extensionErrorEvent = CustomEvent<{
  code: number;
  description: string;
  key: string;  
}>;

declare global {
  interface BryWebCollectorComponent extends HTMLElement {
    // And this
    // addEventListener<K extends keyof BryWebCollectorComponentEventMap>(
    //   type: K,
    //   listener: (
    //     this: BryWebCollectorComponent,
    //     ev: BryWebCollectorComponentEventMap[K]
    //   ) => unknown,
    //   options?: boolean | AddEventListenerOptions
    // ): void;
    // removeEventListener<K extends keyof BryWebCollectorComponentEventMap>(
    //   type: K,
    //   listener: (
    //     this: BryWebCollectorComponent,
    //     ev: BryWebCollectorComponentEventMap[K]
    //   ) => unknown,
    //   options?: boolean | EventListenerOptions
    // ): void;

    // PROPS
    [Props.EXTENSION_NAME]: string;
    [Props.COLLECTOR_SELECT]: 'BOTH' | 'FINGERS' | 'FACE' | 'DOCUMENT';
    [Props.VIDEO_DIMENSIONS]: string;
    [Props.ENABLE_MINUTIAE]: string;
    [Props.WEIGHTS_PATH]: string;
    [Props.LIVENESS_ENABLE]: string;
    [Props.IMPORT_LOTTIE]: string;
    [Props.HIDE_TABS]: string;
    [Props.IMPORT_EXTENSION_SCRIPT]: string;
    [Props.EXTENSION_URL_SCRIPT]: string;
    [Props.EVALUATE_PHOTO]: string;
    [Props.SHOW_CAPTURE_BUTTON]: string;
    [Props.SHOW_UNCONFORMITIES]: string;
    [Props.VIDEO_OVERLAY]: string;
    [Props.VIDEO_OVERLAY_TRANSPARENCY]: number;
    [Props.SHOW_CONFIG_BUTTON]: string;
    [Props.SHOW_AUTO_CAPTURE_BUTTON]: string;
    [Props.SHOW_CAMERA_BUTTON]: string;
    [Props.LANGUAGE]: string;
    [Props.SHOW_JUSTIFICATION_FIELD]: string;
    [Props.MIN_EYE_TO_EYE_DIST]: number;
    [Props.SHOW_WATERMARK]: string;
    [Props.FACE_DETECTION_SENSITIVITY]: string;
    /**
     * Clears fingers and face, to make ready for a new collection.
     * Will not clear jwtToken.
     */
    reset(): void;
    setCode(usrCode: string): this;
    setId(requestID: string): this;
    setBioAcJWTToken(token: string, bioacUrl: string, validateBiometricsUrl: string): this;
    getJustification(): string;
    /**
     * Wether to send a finger-cleared message whenever the clear btn is clicked.
     *
     */
    setNotifyFingersCleared(newValue: boolean): this;
    /**
     *  Sets the face collector component within the web component. This is required when changing tabs in the embedded application.
     *  This is required because of a svelte issue. The component's onDestroy never actually gets called and therefore the on mount
     *  doesn't get called so we have to compensate that here. Hopefully in svelte version 4 that issue will get fixed.
     * */
    setFaceCollectorComponent(): Promise<this>;
    /**
     * You may disable face Api in case your computer isn't powerful enough.
     */
    setEnableFaceDetector(enabled: boolean): this;
    /**
     * You may define a list of fingers and their base64 values that can be captured.
     * This forces the capture process to match the given finger at the given position, and stopping otherwise.
     * Only works in wasm mode and requires agrAuthentication to be true
     * @param _requiredFingers
     */
    setRequiredFingers(
      _requiredFingers: {
        data: string;
        bodyPart: FingerName;
      }[]
    ): Promise<this>;
    /**
     * Sets pre collected fingers. The component will show the fingers as if they had
     * been just collected.
     */
    setCollectedFingers(
      fingers: Array<{
        bodyPart: number | BodyPartNames;
        data: string;
        img?: string;
        nfiq?: number;
      }>
    ): Promise<this>;
    setLivenessEndpoint(url: string): this;
    setEnableLiveness(nv: boolean): this;
    setShowLivenessResultToast(nv: boolean): this;
    verify(
      missingFingers: Array<number | BodyPartNames>,
      unavailableFingers: Array<number | BodyPartNames>,
      automaticFingers: Array<number | BodyPartNames>,
      code: string
    ): Promise<void>;
    update(
      missingFingers: Array<number | BodyPartNames>,
      unavailableFingers: Array<number | BodyPartNames>,
      automaticFingers: Array<number | BodyPartNames>,
      code: string
    ): Promise<void>;
    /**
     * Sets up the component to perform an enroll according to the PSBIO rules
     */
    enroll(code: string): Promise<void>;
    verifyAgr(
      missingFingers: Array<number | BodyPartNames>,
      unavailableFingers: Array<number | BodyPartNames>,
      automaticFingers: Array<number | BodyPartNames>,
      blacklistedFingers: { data: string; bodyPart: FingerName }[],
      code: string,
      agrCode: string
    ): Promise<void>;
  }
  interface HTMLElementTagNameMap {
    'biometric-collector': this;
  }
  interface WindowEventMap {
    'export-face': exportFace;
    'export-document': exportDocument;
    'face-unconformities-validated': faceUnconformitiesValidated;
    'document-unconformities-validated': documentUnconformitiesValidated;
    'extension-error': extensionErrorEvent;
  }
}
