/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { BusinessError, AsyncCallback, Callback} from '@ohos.base';
import { Resource } from 'global.resource';

native function sendAccessibilityEventSync(event: accessibility.EventInfo): void;

export enum AccessibilityAction {
  ACCESSIBILITY_FOCUS = 0,
  CLEAR_ACCESSIBILITY_FOCUS = 1,
  FOCUS = 2,
  CLEAR_FOCUS = 3,
  CLICK = 4,
  LONG_CLICK = 5,
  CUT = 6,
  COPY = 7,
  PASTE = 8,
  SELECT = 9,
  SET_TEXT = 10,
  SCROLL_FORWARD = 11,
  SCROLL_BACKWARD = 12,
  SET_SELECTION = 13,
  SET_CURSOR_POSITION = 14,
  HOME = 15,
  BACK = 16,
  RECENT_TASK = 17,
  NOTIFICATION_CENTER = 18,
  CONTROL_CENTER = 19,
  SPAN_CLICK = 20,
  INJECT_ACTION = 21,
  EXECUTE_CUSTOM_ACTION = 22
}

export enum AccessibilityFocusScene {
  HOVER_FOCUS = 1,
  SWIPE_FOCUS = 2,
  SCROLL_FOCUS = 3
}

export enum AccessibilityEventType {
  TYPE_ACCESSIBILITY_FOCUS = 0,
  TYPE_ACCESSIBILITY_FOCUS_CLEAR = 1,
  TYPE_CLICK = 2,
  TYPE_LONG_CLICK = 3,
  TYPE_SELECT = 4,
  TYPE_HOVER_ENTER = 5,
  TYPE_HOVER_EXIT = 6,
  TYPE_FOCUS = 7,
  TYPE_TEXT_UPDATE = 8,
  TYPE_TEXT_SELECTION_UPDATE = 9,
  TYPE_SCROLL = 10,
  TYPE_REQUEST_FOCUS_FOR_ACCESSIBILITY = 11,
  TYPE_ANNOUNCE_FOR_ACCESSIBILITY = 12,
  TYPE_REQUEST_FOCUS_FOR_ACCESSIBILITY_NOT_INTERRUPT = 13,
  TYPE_ANNOUNCE_FOR_ACCESSIBILITY_NOT_INTERRUPT = 14,
  TYPE_ELEMENT_INFO_CHANGE = 15,
  TYPE_SCROLLING = 16,
  TYPE_WINDOW_ADD = 17,
  TYPE_WINDOW_REMOVE = 18,
  TYPE_WINDOW_BOUNDS = 19,
  TYPE_WINDOW_ACTIVE = 20,
  TYPE_WINDOW_FOCUS = 21,
  TYPE_WINDOW_PROPERTY = 22,
  TYPE_WINDOW_LAYER = 23,
  TYPE_TOUCH_BEGIN = 24,
  TYPE_TOUCH_END = 25,
  TYPE_PAGE_CONTENT_UPDATE = 26,
  TYPE_PAGE_STATE_UPDATE = 27,
  TYPE_PAGE_OPEN = 28,
  TYPE_PAGE_CLOSE = 29,
  TYPE_SWIPE_LEFT = 30,
  TYPE_SWIPE_LEFT_THEN_RIGHT = 31,
  TYPE_SWIPE_LEFT_THEN_UP = 32,
  TYPE_SWIPE_LEFT_THEN_DOWN = 33,
  TYPE_SWIPE_RIGHT = 34,
  TYPE_SWIPE_RIGHT_THEN_LEFT = 35,
  TYPE_SWIPE_RIGHT_THEN_UP = 36,
  TYPE_SWIPE_RIGHT_THEN_DOWN = 37,
  TYPE_SWIPE_UP = 38,
  TYPE_SWIPE_UP_THEN_LEFT = 39,
  TYPE_SWIPE_UP_THEN_RIGHT = 40,
  TYPE_SWIPE_UP_THEN_DOWN = 41,
  TYPE_SWIPE_DOWN = 42,
  TYPE_SWIPE_DOWN_THEN_LEFT = 43,
  TYPE_SWIPE_DOWN_THEN_RIGHT = 44,
  TYPE_SWIPE_DOWN_THEN_UP = 45,
  TYPE_TWO_FINGER_SINGLE_TAP = 46,
  TYPE_TWO_FINGER_DOUBLE_TAP = 47,
  TYPE_TWO_FINGER_DOUBLE_TAP_AND_HOLD = 48,
  TYPE_TWO_FINGER_TRIPLE_TAP = 49,
  TYPE_TWO_FINGER_TRIPLE_TAP_AND_HOLD = 50,
  TYPE_THREE_FINGER_SINGLE_TAP = 51,
  TYPE_THREE_FINGER_DOUBLE_TAP = 52,
  TYPE_THREE_FINGER_DOUBLE_TAP_AND_HOLD = 53,
  TYPE_THREE_FINGER_TRIPLE_TAP = 54,
  TYPE_THREE_FINGER_TRIPLE_TAP_AND_HOLD = 55,
  TYPE_FOUR_FINGER_SINGLE_TAP = 56,
  TYPE_FOUR_FINGER_DOUBLE_TAP = 57,
  TYPE_FOUR_FINGER_DOUBLE_TAP_AND_HOLD = 58,
  TYPE_FOUR_FINGER_TRIPLE_TAP = 59,
  TYPE_FOUR_FINGER_TRIPLE_TAP_AND_HOLD = 60,
  TYPE_THREE_FINGER_SWIPE_UP = 61,
  TYPE_THREE_FINGER_SWIPE_DOWN = 62,
  TYPE_THREE_FINGER_SWIPE_LEFT = 63,
  TYPE_THREE_FINGER_SWIPE_RIGHT = 64,
  TYPE_FOUR_FINGER_SWIPE_UP = 65,
  TYPE_FOUR_FINGER_SWIPE_DOWN = 66,
  TYPE_FOUR_FINGER_SWIPE_LEFT = 67,
  TYPE_FOUR_FINGER_SWIPE_RIGHT = 68,
  TYPE_PAGE_ACTIVE = 69,
  TYPE_NOTIFICATION_UPDATE_EVENT = 70,
  TYPE_FOCUS_INVISIBLE = 71,
  TYPE_ONE_FINGER_DOUBLE_TAP = 72
}

namespace accessibility {
    loadLibraryWithPermissionCheck("accessibility_ani", "@ohos.accessibility");

    export type EventType = 'accessibilityFocus' | 'accessibilityFocusClear' |
        'click' | 'longClick' | 'focus' | 'select' | 'hoverEnter' | 'hoverExit' |
        'textUpdate' | 'textSelectionUpdate' | 'scroll' | 'requestFocusForAccessibility' |
        'announceForAccessibility' | 'requestFocusForAccessibilityNotInterrupt' |
        'announceForAccessibilityNotInterrupt' | 'scrolling' | 'pageActive' | 'notificationUpdate' | 'focusInvisible';

    export type Action = 'accessibilityFocus' | 'clearAccessibilityFocus' | 'focus' | 'clearFocus' | 'clearSelection' |
        'click' | 'longClick' | 'cut' | 'copy' | 'paste' | 'select' | 'setText' | 'delete' |
        'scrollForward' | 'scrollBackward' | 'setSelection' | 'setCursorPosition' | 'home' |
        'back' | 'recentTask' | 'notificationCenter' | 'controlCenter' | 'common' | 'injectAction' | 'executeCustomAction';

    export type WindowUpdateType = 'add' | 'remove' | 'bounds' | 'active' | 'focus';

    export type TextMoveUnit = 'char' | 'word' | 'line' | 'page' | 'paragraph';

    export type observerType = 'accessibilityStateChange' | 'touchGuideStateChange' | 'screenReaderStateChange' |
        'touchModeChange' | 'audioMonoStateChange' | 'animationReduceStateChange' | 'flashReminderStateChange'|
        'seniorModeStateChange';

    export type AbilityType = 'audible' | 'generic' | 'haptic' | 'spoken' | 'visual' | 'all';

    export type AbilityState = 'enable' | 'disable' | 'install';

    export type Capability = 'retrieve' | 'touchGuide' | 'keyEventObserver' | 'zoom' | 'gesture';

    export native function isOpenTouchGuideSync(): boolean;

    export native function isOpenAccessibilitySync(): boolean;

    export native function isScreenReaderOpenSync(): boolean;

    export native function getTouchModeSync(): string;

    export native function getAccessibilityExtensionListSync(abilityType: AbilityType, stateType: AbilityState
        ): Array<AccessibilityAbilityInfo>;

    export function getAccessibilityExtensionList(abilityType: AbilityType,
        stateType: AbilityState): Promise<Array<AccessibilityAbilityInfo>> {
        return new Promise<Array<AccessibilityAbilityInfo>> ((resolve: (v: Array<AccessibilityAbilityInfo>) => void,
            reject: (error: BusinessError) => void): void => {
            taskpool.execute(getAccessibilityExtensionListSync, abilityType, stateType).then((code :Any): void => {
                if (Array.isArray(code)) {
                    resolve(code as Array<AccessibilityAbilityInfo>);
                } else {
                    resolve([] as Array<AccessibilityAbilityInfo>);
                }
            }).catch((err: Any): void => {
                reject(err as BusinessError);
            });
        });
    }

    export function getAccessibilityExtensionList(abilityType: AbilityType, stateType: AbilityState,
        callback: AsyncCallback<Array<AccessibilityAbilityInfo>>
    ): void {
        let p1 = taskpool.execute(getAccessibilityExtensionListSync, abilityType, stateType);
        p1.then((ret: Any): void => {
            if (Array.isArray(ret)) {
                callback(new BusinessError(), ret as Array<AccessibilityAbilityInfo>);
            } else {
                callback(new BusinessError(), [] as Array<AccessibilityAbilityInfo>);
            }
        }).catch((err: Any): void => {
            callback(err as BusinessError, [] as Array<AccessibilityAbilityInfo>)
        });
    }

    native function onStateChange(type: observerType, callback: Callback<boolean>): void;

    export function onAccessibilityStateChange(callback: Callback<boolean>): void {
        onStateChange('accessibilityStateChange', callback);
    }

    export function onTouchGuideStateChange(callback: Callback<boolean>): void {
        onStateChange('touchGuideStateChange', callback);
    }

    export function onScreenReaderStateChange(callback: Callback<boolean>): void {
        onStateChange('screenReaderStateChange', callback);
    }

    native function onTouchModeChangeNative(type: observerType, callback: Callback<string>): void;

    export function onTouchModeChange(callback: Callback<string>): void {
        onTouchModeChangeNative('touchModeChange', callback);
    }

    native function offTouchModeChangeNative(type: observerType, callback: Callback<string>): void;

    native function offStateChange(type: observerType, callback: Callback<boolean>): void;

    native function offAll(type: observerType): void;

    export function offAccessibilityStateChange(callback?: Callback<boolean>): void {
        if (callback === undefined) {
            offAll('accessibilityStateChange');
        } else {
            let callbackFunc: Callback<boolean> = callback as Callback<boolean>;
            offStateChange('accessibilityStateChange', callbackFunc);
        }
    }

    export function offTouchGuideStateChange(callback?: Callback<boolean>): void {
        if (callback === undefined) {
            offAll('touchGuideStateChange');
        } else {
            let callbackFunc: Callback<boolean> = callback as Callback<boolean>;
            offStateChange('touchGuideStateChange', callbackFunc);
        }
    }

    export function offScreenReaderStateChange(callback?: Callback<boolean>): void {
        if (callback === undefined) {
            offAll('screenReaderStateChange');
        } else {
            let callbackFunc: Callback<boolean> = callback as Callback<boolean>;
            offStateChange('screenReaderStateChange', callbackFunc);
        }
    }

    export function offTouchModeChange(callback?: Callback<string>): void {
        if (callback === undefined) {
            offAll('touchModeChange');
        } else {
            let callbackFunc: Callback<string> = callback as Callback<string>;
            offTouchModeChangeNative('touchModeChange', callbackFunc);
        }
    }

    export native function getCaptionsManager(): CaptionsManager;

    native function isAudioMonoEnabledSync(): boolean;

    export function isAudioMonoEnabled(): Promise<boolean> {
        return new Promise<boolean>((resolve: (v: boolean) => void, reject: (error: BusinessError) => void): void => {
            taskpool.execute((): boolean => {
                return isAudioMonoEnabledSync();
            })
            .then((ret: Any): void => {
                resolve(ret as boolean);
            })
            .catch((ret: Any): void => {
                reject(ret as BusinessError);
            });
        });
    }

    export function onAudioMonoStateChange(callback: Callback<boolean>): void {
        onStateChange('audioMonoStateChange', callback);
    }

    export function offAudioMonoStateChange(callback?: Callback<boolean>): void {
        if (callback === undefined) {
            offAll('audioMonoStateChange');
        } else {
            let callbackFunc: Callback<boolean> = callback as Callback<boolean>;
            offStateChange('audioMonoStateChange', callbackFunc);
        }
    }

    native function isAnimationReduceEnabledSync(): boolean;

    export function isAnimationReduceEnabled(): Promise<boolean> {
        return new Promise<boolean>((resolve: (v: boolean) => void, reject: (error: BusinessError) => void): void => {
            taskpool.execute((): boolean => {
                return isAnimationReduceEnabledSync();
            })
            .then((ret: Any): void => {
                resolve(ret as boolean);
            })
            .catch((ret: Any): void => {
                reject(ret as BusinessError);
            });
        });
    }

    export function onAnimationReduceStateChange(callback: Callback<boolean>): void {
        onStateChange('animationReduceStateChange', callback);
    }

    export function offAnimationReduceStateChange(callback?: Callback<boolean>): void {
        if (callback === undefined) {
            offAll('animationReduceStateChange');
        } else {
            let callbackFunc: Callback<boolean> = callback as Callback<boolean>;
            offStateChange('animationReduceStateChange', callbackFunc);
        }
    }

    native function isFlashReminderEnabledSync(): boolean;

    export function isFlashReminderEnabled(): Promise<boolean> {
        return new Promise<boolean>((resolve: (v: boolean) => void, reject: (error: BusinessError) => void): void => {
            taskpool.execute((): boolean => {
                return isFlashReminderEnabledSync();
            })
            .then((ret: Any): void => {
                resolve(ret as boolean);
            })
            .catch((ret: Any): void => {
                reject(ret as BusinessError);
            });
        });
    }

    export function onFlashReminderStateChange(callback: Callback<boolean>): void {
        onStateChange('flashReminderStateChange', callback);
    }

    export function offFlashReminderStateChange(callback?: Callback<boolean>): void {
        if (callback === undefined) {
            offAll('flashReminderStateChange');
        } else {
            let callbackFunc: Callback<boolean> = callback as Callback<boolean>;
            offStateChange('flashReminderStateChange', callbackFunc);
        }
    }

    export native function isSeniorModeOpenSync(): boolean;

    export function isSeniorModeEnabled(): Promise<boolean> {
        return new Promise<boolean>((resolve: (v: boolean) => void, reject: (error: BusinessError) => void): void => {
            taskpool.execute((): boolean => {
                return isSeniorModeOpenSync();
            })
            .then((ret: Any): void => {
                resolve(ret as boolean);
            })
            .catch((ret: Any): void => {
                reject(ret as BusinessError);
            });
        });
    }

    export function onSeniorModeStateChange(callback: Callback<boolean>): void {
        onStateChange('seniorModeStateChange', callback);
    }

    export function offSeniorModeStateChange(callback?: Callback<boolean>): void {
        if (callback === undefined) {
            offAll('seniorModeStateChange');
        } else {
            let callbackFunc: Callback<boolean> = callback as Callback<boolean>;
            offStateChange('seniorModeStateChange', callbackFunc);
        }
    }

    export native function onSeniorModeStateChangeForSelfSync(callback: Callback<boolean>): void;

    export function onSeniorModeStateChangeForSelf(callback: Callback<boolean>): void {
        onSeniorModeStateChangeForSelfSync(callback);
    }

    export native function offSeniorModeStateChangeForSelfSync(callback?: Callback<boolean>): void;

    export function offSeniorModeStateChangeForSelf(callback?: Callback<boolean>): void {
        offSeniorModeStateChangeForSelfSync(callback);
    }

    export native function getSeniorModeStateForSelfSync(): boolean;

    export function getSeniorModeStateForSelf(): Promise<boolean> {
        return new Promise<boolean>((resolve: (v: boolean) => void, reject: (error: BusinessError) => void): void => {
            taskpool.execute((): boolean => {
                return getSeniorModeStateForSelfSync();
            })
            .then((ret: Any): void => {
                resolve(ret as boolean);
            })
            .catch((ret: Any): void => {
                reject(ret as BusinessError);
            });
        });
    }

    export native function setSeniorModeStateForSelfSync(state: boolean): void;

    export function setSeniorModeStateForSelf(state: boolean): Promise<void> {
        return new Promise<void>((resolve, reject): void => {
            taskpool.execute((): void => {
                return setSeniorModeStateForSelfSync(state);
            })
            .then((ret: Any): void => {
                resolve(ret as undefined);
            })
            .catch((ret: Any): void => {
                reject(ret as BusinessError);
            });
        });
    }

    export interface CaptionsManager {
        enabled: boolean;
        style: CaptionsStyle;
        onEnableChange(callback: Callback<boolean>): void;
        onStyleChange(callback: Callback<CaptionsStyle>): void;
        offEnableChange(callback?: Callback<boolean>): void;
        offStyleChange(callback?: Callback<CaptionsStyle>): void;
    }

    export class CaptionsManagerImpl implements CaptionsManager {
        native getEnabled(): boolean;
        native getStyle(): CaptionsStyle;
        native setEnabled(value: boolean): void;
        native setStyle(value: CaptionsStyle): void;
        get enabled(): boolean {
            return this.getEnabled();
        }
        get style(): CaptionsStyle {
            return this.getStyle();
        }
        set enabled(value: boolean) {
            this.setEnabled(value);
        }
        set style(value: CaptionsStyle) {
            this.setStyle(value);
        }

        native onEnableChange(callback: Callback<boolean>): void;
        native onStyleChange(callback: Callback<CaptionsStyle>): void;

        native offEnableChangeWithCallback(callback: Callback<boolean>): void;
        native offEnableChangeAll(): void;
        native offStyleChangeWithCallback(callback: Callback<CaptionsStyle>): void;
        native offStyleChangeAll(): void;
        offEnableChange(callback?: Callback<boolean>): void {
            if (callback === undefined) {
                this.offEnableChangeAll();
            } else {
                let callbackFunc: Callback<boolean> = callback as Callback<boolean>;
                this.offEnableChangeWithCallback(callbackFunc);
            }
        }
        offStyleChange(callback?: Callback<CaptionsStyle>): void {
            if (callback === undefined) {
                this.offStyleChangeAll();
            } else {
                let callbackFunc: Callback<CaptionsStyle> = callback as Callback<CaptionsStyle>;
                this.offStyleChangeWithCallback(callbackFunc);
            }
        }
    }

    export type CaptionsFontEdgeType = 'none' | 'raised' | 'depressed' | 'uniform' | 'dropShadow';

    export type CaptionsFontFamily = 'default' | 'monospacedSerif' | 'serif' | 'monospacedSansSerif' | 'sansSerif' |
        'casual' | 'cursive' | 'smallCapitals';

    export interface CaptionsStyle {
        fontFamily: CaptionsFontFamily;

        fontScale: int;

        fontColor: int | string;

        fontEdgeType: CaptionsFontEdgeType;

        backgroundColor: int | string;

        windowColor: int | string;
    }

    export class CaptionsStyleImpl implements CaptionsStyle {
        fontFamily: CaptionsFontFamily = 'default';

        fontScale: int = 75;

        fontColor: int | string = 0xff0000;

        fontEdgeType: CaptionsFontEdgeType = 'none';

        backgroundColor: int | string = 0xff0000;

        windowColor: int | string = 0xff0000;
    }

    export interface AccessibilityAbilityInfo {
        id: string;
        name: string;
        bundleName: string;
        targetBundleNames: Array<string>;
        abilityTypes: Array<AbilityType>;
        capabilities: Array<Capability>;
        description: string;
        eventTypes: Array<EventType>;
        needHide: boolean;
        label: string;
    }

    class AccessibilityAbilityInfoImpl implements AccessibilityAbilityInfo {
        id: string = "";
        name: string = "";
        bundleName: string = "";
        targetBundleNames: Array<string> = [];
        abilityTypes: Array<AbilityType> = [];
        capabilities: Array<Capability> = [];
        description: string = "";
        eventTypes: Array<EventType> = [];
        needHide: boolean = false;
        label: string = "";
    }

    export class EventInfo {
        constructor(type: EventType, bundleName: string, triggerAction: Action) {
            this.type = type;
            this.bundleName = bundleName;
            this.triggerAction = triggerAction;
        }
        type: EventType;
        windowUpdateType?: WindowUpdateType;
        bundleName: string;
        componentType?: string;
        pageId?: int;
        description?: string;
        triggerAction: Action;
        textMoveUnit?: TextMoveUnit;
        contents?: Array<string>;
        lastContent?: string;
        beginIndex?: int;
        currentIndex?: int;
        endIndex?: int;
        itemCount?: int;
        elementId?: int;
        textAnnouncedForAccessibility?: string;
        textResourceAnnouncedForAccessibility?: Resource;
        customId?: string;
    }

    export function sendAccessibilityEvent(event: EventInfo, callback: AsyncCallback<void>): void {
        taskpool.execute((): void => {
            return sendAccessibilityEventSync(event);
        })
        .then((ret: Any): void => {
            callback(new BusinessError(), ret as undefined);
        })
        .catch((ret: Any): void => {
            callback(ret as BusinessError, undefined);
        });
    }

    export function sendAccessibilityEvent(event: EventInfo): Promise<void> {
        return new Promise<void>((resolve, reject): void => {
            taskpool.execute((): void => {
                return sendAccessibilityEventSync(event);
            })
            .then((ret: Any): void => {
                resolve(ret as undefined);
            })
            .catch((ret: Any): void => {
                reject(ret as BusinessError);
            });
        });
    }
}
export default accessibility;

export enum FocusMoveResultCode {
  NOT_SUPPORTED = -1,
  SEARCH_SUCCESS = 0,
  SEARCH_SUCCESS_NEXT_BYPASS_DESCENDANTS = 1,
  SEARCH_FAILURE = 2,
  SEARCH_FAILURE_IN_CHILD_TREE = 3,
  SEARCH_FAILURE_LOST_NODE = 4,
  SEARCH_NEXT = 5,
  DOUBLE_CHECK_CHILD_PROPERTY = 6,
  DOUBLE_CHECK_CHILD_PROPERTY_AND_GET_LAST = 7,
  SEARCH_FAILURE_IN_SCROLL = 8
}

export enum FocusRuleType {
  DEFAULT = 1,
  FOCUS_BY_LINK = 2,
  FOCUS_BY_TITLE = 3,
}

export enum InjectActionType {
  CLICK = 1,
  DOUBLE_CLICK = 2,
  LONG_CLICK = 3
}

export enum OperateVirtualNodeResult {
  SUCCESS = 0,
  ACCESSIBILITY_ELEMENT_NOT_EXIST = 1,
  CANNOT_MODIFY_ROOT_NODE = 2,
  ACCESSIBILITY_PROPERTY_EMPTY = 3,
  ALLOCATE_ID_FAILED = 4,
  ADD_NODE_IS_EMPTY = 5,
  INTERNAL_ERROR = 6,
  VIRTUAL_NODE_NOT_SUPPORT = 7,
}