// (C) 2021-2026 GoodData Corporation
import { call, put, select } from "redux-saga/effects";
import { invariant } from "ts-invariant";
import { serializeObjRef } from "@gooddata/sdk-model";
import { createExportFunction, prepareGeoInsightForDataExport, } from "@gooddata/sdk-ui";
import { createExportExecutionDefinition } from "@gooddata/sdk-ui/internal";
import { invalidArgumentsProvided } from "../../events/general.js";
import { insightWidgetExportRequested, insightWidgetExportResolved, } from "../../events/insight.js";
import { selectCatalogAttributes } from "../../store/catalog/catalogSelectors.js";
import { selectExportResultPollingTimeout, selectSettings } from "../../store/config/configSelectors.js";
import { selectExecutionResultByRef, selectIsExecutionResultExportableToCsvByRef, selectIsExecutionResultExportableToPdfByRef, selectIsExecutionResultExportableToXlsxByRef, selectIsExecutionResultReadyForExportByRef, } from "../../store/executionResults/executionResultsSelectors.js";
import { selectInsightByWidgetRef } from "../../store/insights/insightsSelectors.js";
import { selectPreloadedAttributesWithReferences } from "../../store/tabs/filterContext/filterContextSelectors.js";
async function performExport(ctx, executionResult, config, exportDefinition) {
    const exportExecutionResult = exportDefinition
        ? await ctx.backend.workspace(ctx.workspace).execution().forDefinition(exportDefinition).execute()
        : executionResult;
    const exporter = createExportFunction(exportExecutionResult);
    return exporter(config);
}
function* validateIsExportable(ctx, cmd, ref) {
    const isExportable = yield select(selectIsExecutionResultReadyForExportByRef(ref));
    if (!isExportable) {
        throw invalidArgumentsProvided(ctx, cmd, `The widget with ref: ${serializeObjRef(ref)} cannot be exported at the moment.`);
    }
}
function* validateSettingsAndPermissions(ctx, cmd) {
    const { config, ref } = cmd.payload;
    let canExport = false;
    if (config.format === "csv") {
        canExport = (yield select(selectIsExecutionResultExportableToCsvByRef(ref)));
    }
    if (config.format === "xlsx") {
        canExport = (yield select(selectIsExecutionResultExportableToXlsxByRef(ref)));
    }
    if (config.format === "pdf") {
        canExport = (yield select(selectIsExecutionResultExportableToPdfByRef(ref)));
    }
    if (!canExport) {
        throw invalidArgumentsProvided(ctx, cmd, `The widget with ref: ${serializeObjRef(ref)} cannot be exported because the feature is disabled or the user does not have the necessary permissions.`);
    }
}
export function* exportInsightWidgetHandler(ctx, cmd) {
    const { config, ref, insight: payloadInsight } = cmd.payload;
    yield put(insightWidgetExportRequested(ctx, ref, config, cmd.correlationId));
    yield call(validateIsExportable, ctx, cmd, ref);
    yield call(validateSettingsAndPermissions, ctx, cmd);
    const executionEnvelope = yield select(selectExecutionResultByRef(ref));
    // executionResult must be defined at this point
    invariant(executionEnvelope?.executionResult);
    const insight = payloadInsight ?? (yield select(selectInsightByWidgetRef(ref)));
    const settings = yield select(selectSettings);
    const catalogAttributes = yield select(selectCatalogAttributes);
    const preloadedAttributesWithReferences = yield select(selectPreloadedAttributesWithReferences);
    let exportDefinition;
    if (insight) {
        const exportInsight = prepareGeoInsightForDataExport(insight, {
            settings,
            catalogAttributes,
            preloadedAttributesWithReferences,
        }) ?? insight;
        exportDefinition =
            exportInsight === insight
                ? undefined
                : createExportExecutionDefinition(exportInsight, ctx.workspace, executionEnvelope.executionResult.definition);
    }
    const timeout = yield select(selectExportResultPollingTimeout);
    const result = yield call(performExport, ctx, executionEnvelope.executionResult, { ...config, timeout }, exportDefinition);
    // prepend hostname if provided so that the results are downloaded from there, not from where the app is hosted
    const fullUri = ctx.backend.config.hostname
        ? new URL(result.uri, ctx.backend.config.hostname).href
        : result.uri;
    const sanitizedResult = {
        ...result,
        uri: fullUri,
    };
    return insightWidgetExportResolved(ctx, sanitizedResult, cmd.correlationId);
}
