import { FlowRequestDataEnum, FlowResponseDataEnum, FlowSourceEnum } from '../../models/http-flows/HttpFlows.js';
import { ReadDataSourceStepKind } from '../../models/http-flows/steps/data/ReadDataSourceStep.js';
import { ReadValueStepKind } from '../../models/http-flows/steps/data/ReadValueStep.js';
import { AsLowerCaseStepKind } from '../../models/http-flows/steps/transformation/AsLowerCaseStep.js';
import { AsUpperCaseStepKind } from '../../models/http-flows/steps/transformation/AsUpperCaseStep.js';
import { AsNumberStepKind } from '../../models/http-flows/steps/transformation/AsNumberStep.js';
import { RoundStepKind } from '../../models/http-flows/steps/transformation/RoundStep.js';
import { SubstringStepKind } from '../../models/http-flows/steps/transformation/SubstringStep.js';
import { TrimStepKind } from '../../models/http-flows/steps/transformation/TrimStep.js';
import { EqualAssertionKind } from '../../models/http-flows/steps/assertion/EqualAssertion.js';
import { NotEqualAssertionKind } from '../../models/http-flows/steps/assertion/NotEqualAssertion.js';
import { AssertionError } from '../../models/http-flows/AssertionError.js';
import { GreaterThanAssertionKind, } from '../../models/http-flows/steps/assertion/GreaterThanAssertion.js';
import { LessThanAssertionKind } from '../../models/http-flows/steps/assertion/LessThanAssertion.js';
import { IncludesAssertionKind } from '../../models/http-flows/steps/assertion/IncludesAssertion.js';
import { NotIncludesAssertionKind, } from '../../models/http-flows/steps/assertion/NotIncludesAssertion.js';
import { OkAssertionKind } from '../../models/http-flows/steps/assertion/OkAssertion.js';
import { NotOkAssertionKind } from '../../models/http-flows/steps/assertion/NotOkAssertion.js';
import { HttpFlows } from './HttpFlows.js';
/**
 * A class that perform assertions that have been defined on an HTTP request.
 */
export class HttpAssertionRunner extends HttpFlows {
    report = [];
    /**
     *
     * @param request The request object sent to the server
     * @param response The generated response
     * @param assertions The list of assertions to perform.
     */
    async run(request, response, assertions) {
        this.report = [];
        if (!assertions || !assertions.length) {
            return [...this.report];
        }
        for (const assertion of assertions) {
            await this.runAssertion(request, response, assertion);
        }
        return [...this.report];
    }
    async runAssertion(request, response, assertion) {
        const { steps } = assertion;
        if (!Array.isArray(steps) || !steps.length) {
            return;
        }
        // this keeps a value from the last step to be passed to the next step.
        let lastResult = {
            value: undefined,
        };
        let error;
        for (const step of steps) {
            try {
                lastResult = await this.runStep(request, step, lastResult, response);
            }
            catch (e) {
                const typed = e;
                if (typed.name === 'AssertionError') {
                    error = typed;
                }
                else {
                    const err = e;
                    error = new AssertionError({
                        message: err.message,
                    });
                }
                break;
            }
        }
        const description = assertion.description || this.createDescription(steps);
        if (error) {
            this.report.push({
                ok: false,
                description,
                error: error.toJSON(),
            });
        }
        else {
            this.report.push({
                ok: true,
                description,
            });
        }
    }
    createDescription(steps) {
        const parts = [];
        for (const step of steps) {
            switch (step.kind) {
                case ReadDataSourceStepKind:
                    parts.push(this.getDataSourceStepLabel(step));
                    break;
                case ReadValueStepKind:
                    parts.push(this.getValueStepLabel(step));
                    break;
                case AsLowerCaseStepKind:
                    parts.push('To lower case');
                    break;
                case AsUpperCaseStepKind:
                    parts.push('To upper case');
                    break;
                case AsNumberStepKind:
                    parts.push('As number');
                    break;
                case RoundStepKind:
                    parts.push('Round');
                    break;
                case TrimStepKind:
                    parts.push('Trim');
                    break;
                case SubstringStepKind:
                    parts.push('Substring');
                    break;
                case EqualAssertionKind:
                    parts.push(`Equals to ${step.value}`);
                    break;
                case NotEqualAssertionKind:
                    parts.push(`Not equals to ${step.value}`);
                    break;
                case GreaterThanAssertionKind:
                    parts.push(`Is greater than ${step.value}`);
                    break;
                case LessThanAssertionKind:
                    parts.push(`Is less than ${step.value}`);
                    break;
                case IncludesAssertionKind:
                    parts.push(`Includes ${step.value}`);
                    break;
                case NotIncludesAssertionKind:
                    parts.push(`Not includes ${step.value}`);
                    break;
                case OkAssertionKind:
                    parts.push(`Is OK`);
                    break;
                case NotOkAssertionKind:
                    parts.push(`Is not OK`);
                    break;
                default:
            }
        }
        return parts.filter((i) => !!i).join(' > ');
    }
    getDataSourceStepLabel(step) {
        if (step.source === FlowSourceEnum.request) {
            if (step.data === FlowRequestDataEnum.url) {
                return 'Request URL';
            }
            if (step.data === FlowRequestDataEnum.headers) {
                return 'Request headers';
            }
            if (step.data === FlowRequestDataEnum.method) {
                return 'HTTP method';
            }
            if (step.data === FlowRequestDataEnum.body) {
                return 'Request body';
            }
        }
        if (step.source === FlowSourceEnum.response) {
            if (step.data === FlowResponseDataEnum.url) {
                return 'Response URL';
            }
            if (step.data === FlowResponseDataEnum.headers) {
                return 'Response headers';
            }
            if (step.data === FlowResponseDataEnum.body) {
                return 'Response body';
            }
            if (step.data === FlowResponseDataEnum.status) {
                return 'Status code';
            }
            if (step.data === FlowResponseDataEnum.statusText) {
                return 'Status message';
            }
        }
        return 'Invalid step';
    }
    getValueStepLabel(step) {
        const { path } = step;
        return path || '';
    }
}
//# sourceMappingURL=HttpAssertionRunner.js.map