// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { createGetLroStatusFromResponse, createInitializeState, createPoll } from "./stateMachine";
import { getPollingUrl } from "./requestUtils";
import { logger } from "./logger";
export class GenericPollOperation {
    constructor(state, lro, lroResourceLocationConfig, processResult, updateState, isDone) {
        this.state = state;
        this.lro = lro;
        this.lroResourceLocationConfig = lroResourceLocationConfig;
        this.processResult = processResult;
        this.updateState = updateState;
        this.isDone = isDone;
    }
    setPollerConfig(pollerConfig) {
        this.pollerConfig = pollerConfig;
    }
    /**
     * General update function for LROPoller, the general process is as follows
     * 1. Check initial operation result to determine the strategy to use
     *  - Strategies: Location, Azure-AsyncOperation, Original Uri
     * 2. Check if the operation result has a terminal state
     *  - Terminal state will be determined by each strategy
     *  2.1 If it is terminal state Check if a final GET request is required, if so
     *      send final GET request and return result from operation. If no final GET
     *      is required, just return the result from operation.
     *      - Determining what to call for final request is responsibility of each strategy
     *  2.2 If it is not terminal state, call the polling operation and go to step 1
     *      - Determining what to call for polling is responsibility of each strategy
     *      - Strategies will always use the latest URI for polling if provided otherwise
     *        the last known one
     */
    async update(options) {
        var _a, _b, _c;
        const state = this.state;
        let lastResponse = undefined;
        if (!state.isStarted) {
            const initializeState = createInitializeState(state, this.lro.requestPath, this.lro.requestMethod);
            lastResponse = await this.lro.sendInitialRequest();
            initializeState(lastResponse);
        }
        if (!state.isCompleted) {
            if (!this.poll || !this.getLroStatusFromResponse) {
                if (!state.config) {
                    throw new Error("Bad state: LRO mode is undefined. Please check if the serialized state is well-formed.");
                }
                const isDone = this.isDone;
                this.getLroStatusFromResponse = isDone
                    ? (response) => (Object.assign(Object.assign({}, response), { done: isDone(response.flatResponse, this.state) }))
                    : createGetLroStatusFromResponse(this.lro, state.config, this.lroResourceLocationConfig);
                this.poll = createPoll(this.lro);
            }
            if (!state.pollingURL) {
                throw new Error("Bad state: polling URL is undefined. Please check if the serialized state is well-formed.");
            }
            const currentState = await this.poll(state.pollingURL, this.pollerConfig, this.getLroStatusFromResponse);
            logger.verbose(`LRO: polling response: ${JSON.stringify(currentState.rawResponse)}`);
            if (currentState.done) {
                state.result = this.processResult
                    ? this.processResult(currentState.flatResponse, state)
                    : currentState.flatResponse;
                state.isCompleted = true;
            }
            else {
                this.poll = (_a = currentState.next) !== null && _a !== void 0 ? _a : this.poll;
                state.pollingURL = getPollingUrl(currentState.rawResponse, state.pollingURL);
            }
            lastResponse = currentState;
        }
        logger.verbose(`LRO: current state: ${JSON.stringify(state)}`);
        if (lastResponse) {
            (_b = this.updateState) === null || _b === void 0 ? void 0 : _b.call(this, state, lastResponse === null || lastResponse === void 0 ? void 0 : lastResponse.rawResponse);
        }
        else {
            logger.error(`LRO: no response was received`);
        }
        (_c = options === null || options === void 0 ? void 0 : options.fireProgress) === null || _c === void 0 ? void 0 : _c.call(options, state);
        return this;
    }
    async cancel() {
        this.state.isCancelled = true;
        return this;
    }
    /**
     * Serializes the Poller operation.
     */
    toString() {
        return JSON.stringify({
            state: this.state,
        });
    }
}
//# sourceMappingURL=operation.js.map