import * as rxjs from 'rxjs';
import { Observable } from 'rxjs';
import { ClassConstructor } from 'class-transformer';

type KeypointName = "nose" | "left_eye_inner" | "left_eye" | "left_eye_outer" | "right_eye_inner" | "right_eye" | "right_eye_outer" | "left_ear" | "right_ear" | "mouth_left" | "mouth_right" | "left_shoulder" | "right_shoulder" | "left_elbow" | "right_elbow" | "left_wrist" | "right_wrist" | "left_pinky" | "right_pinky" | "left_index" | "right_index" | "left_thumb" | "right_thumb" | "left_hip" | "right_hip" | "left_knee" | "right_knee" | "left_ankle" | "right_ankle" | "left_heel" | "right_heel" | "left_foot_index" | "right_foot_index";

type Size = {
    width: number;
    height: number;
};
type Pose = {
    keypoints: Keypoint[];
    stickpoints?: Omit<Keypoint, 'z' | 'score'>[];
    size: Size;
};
interface Keypoint {
    x: number;
    y: number;
    z: number;
    score: number;
    name: KeypointName;
}
type KeypointCoordinates = Pick<Keypoint, 'x' | 'y' | 'z'>;

interface Operator<In, Out> {
    init(): Promise<void>;
    operator(source: Observable<In>): Observable<Out>;
}
declare abstract class AbstractOperator<In, Out> implements Operator<In, Out> {
    init(): Promise<void>;
    abstract operator(source: Observable<In>): Observable<Out>;
}
declare abstract class PoseOperator extends AbstractOperator<Pose, Pose> {
}

type DtwWorkoutCycleOptions = {
    dtwThreshold?: number;
    retainBufferLength?: number;
};
declare abstract class IDtwWorkoutCycle extends AbstractOperator<Pose, Array<Pose['keypoints']>> {
    protected reference: Array<Pose['keypoints']>;
    protected options: DtwWorkoutCycleOptions;
    protected constructor(reference: Array<Pose['keypoints']>, options: DtwWorkoutCycleOptions);
}

declare class DtwWorkoutCycle extends IDtwWorkoutCycle {
    constructor(options: DtwWorkoutCycleOptions);
    operator(pose$: Observable<Pose>): Observable<Array<Pose['keypoints']>>;
    private add;
}

declare class RelativeMovementFilter extends PoseOperator {
    private readonly threshold;
    constructor(threshold: number);
    operator(pose$: Observable<Pose>): Observable<Pose>;
    private isSignificantMovement;
    relativeMovementDistance(a: Pose['keypoints'], b: Pose['keypoints']): number;
    private euclideanDistances;
    private centroidNormalization;
}

type PoseTrackerOptions = {
    throttleMs?: number;
};
declare class PoseEstimateInput implements AbstractOperator<HTMLVideoElement, Pose> {
    private options;
    private _detector;
    constructor(options?: PoseTrackerOptions);
    operator(video$: Observable<HTMLVideoElement>): Observable<Pose>;
    init(): Promise<void>;
    private estimatePose;
}

declare class ResetOriginOperator extends PoseOperator {
    operator(pose$: Observable<Pose>): Observable<Pose>;
    private normalize;
}

declare class ResetScaleOperator extends PoseOperator {
    operator(pose$: Observable<Pose>): Observable<Pose>;
    private normalize;
    private norm;
}

declare abstract class IKeypointNamesFilter extends PoseOperator {
    protected readonly keypoints: KeypointName[];
    protected constructor(keypoints: KeypointName[]);
}

declare class KeypointNamesFilter extends IKeypointNamesFilter {
    constructor(keypoints: KeypointName[]);
    operator(pose$: Observable<Pose>): Observable<Pose>;
}

type StateMatch = {
    state: string;
    score: number;
};

declare abstract class Response {
    __type: string;
    protected constructor(__type: string);
}
declare class CycleDetected extends Response {
    caloriesBurnt: number;
    stateScores: StateMatch[];
    score: number;
    constructor(caloriesBurnt: number, stateScores?: StateMatch[]);
    private getScore;
}
declare class KeypointsOutOfFrame extends Response {
    keypoints: KeypointName[];
    constructor(keypoints: KeypointName[]);
}
declare class WorkflowResult {
    data?: Response | undefined;
    error?: Response | undefined;
    constructor(data?: Response | undefined, error?: Response | undefined);
}

type FsmWorkoutCycleOptions = {
    similarityThreshold?: number;
};
type Keyframe = {
    name: string;
    pose: Pose['keypoints'];
};
declare abstract class IFsmWorkoutCycle extends AbstractOperator<Pose, CycleDetected> {
    protected readonly reference: Keyframe[];
    protected readonly options: FsmWorkoutCycleOptions;
    protected constructor(reference: Keyframe[], options: FsmWorkoutCycleOptions);
    protected get similarityThreshold(): number;
}

declare class FsmWorkoutCycle extends IFsmWorkoutCycle {
    private _keys;
    private _allowance;
    constructor(options: FsmWorkoutCycleOptions, _keys: string[], _allowance?: number);
    operator(pose$: Observable<Pose>): Observable<CycleDetected>;
    private calculateThreshold;
    private add;
}

declare function htmlImagesObservable(urls: string[]): Observable<ImageBitmap>;
declare function htmlVideoObservable(video: HTMLVideoElement, start?: number, stop?: number): Observable<HTMLVideoElement>;

type WorkflowPayload = {
    operators: Array<{
        __t: string;
        _p: Record<string, any>;
    }>;
};
type PixelInput = ImageData | HTMLVideoElement | HTMLImageElement | HTMLCanvasElement | ImageBitmap;
type ImageSize = {
    width: number;
    height: number;
};

declare abstract class InternalWorkflow {
    protected operators: Operator<any, any>[];
    private __initialized;
    protected constructor(operators: Operator<any, any>[]);
    run(input: Observable<any>): Observable<WorkflowResult>;
    init(): Promise<void>;
    protected serialize(): WorkflowPayload;
    protected static deserialize(data: WorkflowPayload, operatorClasses: ClassConstructor<Operator<any, any>>[]): {
        operators: Operator<any, any>[];
    };
    protected handleErrorsAndContinue: rxjs.UnaryFunction<Observable<Response>, Observable<WorkflowResult>>;
}

declare class Workflow extends InternalWorkflow {
    constructor(...operators: Operator<any, any>[]);
    toJSON(): string;
    static fromJSON(json: string): Workflow;
    toObject(): Record<string, any>;
    static fromObject(obj: WorkflowPayload): Workflow;
}

declare const setVisionTaskAssetBaseURL: (url: string) => void;
declare const setVisionTaskAssetBaseURLFromCdn: () => void;
declare const getVisionTaskAssetBaseURL: () => string;
declare const MAX_SIMILARITY_THRESHOLD = 2.1;

declare const Operators: {
    RelativeMovementFilter: typeof RelativeMovementFilter;
    KeypointNamesFilter: typeof KeypointNamesFilter;
    PoseEstimateInput: typeof PoseEstimateInput;
    ResetOriginOperator: typeof ResetOriginOperator;
    ResetScaleOperator: typeof ResetScaleOperator;
    DtwWorkoutCycle: typeof DtwWorkoutCycle;
    FsmWorkoutCycle: typeof FsmWorkoutCycle;
};

export { CycleDetected, type ImageSize, type Keypoint, type KeypointCoordinates, KeypointsOutOfFrame, MAX_SIMILARITY_THRESHOLD, Operators, type PixelInput, type Pose, Response, type Size, Workflow, type WorkflowPayload, WorkflowResult, getVisionTaskAssetBaseURL, htmlImagesObservable, htmlVideoObservable, setVisionTaskAssetBaseURL, setVisionTaskAssetBaseURLFromCdn };
