// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { CreateTaskErrorReason, FeatureMode, PerformActionsErrorReason } from '../../glic_api/glic_api.js';
import { enumFromClient, enumToClient } from '../enum_conversions.js';
import { bitmapN32ToRGBAImage, byteArrayFromClient, getArrayBufferFromBigBuffer, idFromClient, idToClient, optionalFromClient, optionalToClient, originToClient, tabContextOptionsFromClient, tabContextToClient, urlToClient } from '../host/conversions.js';
import { ErrorWithReasonImpl } from '../request_types.js';
import { assertNever } from '../transport/messaging.js';
export class ActorHostMessageHandler {
    actorHandler;
    constructor(actorHandler) {
        this.actorHandler = actorHandler;
    }
    async getContextForActorFromTab(request, extras) {
        const { result: { errorReason, tabContext } } = await this.actorHandler.getContextForActorFromTab(idFromClient(request.tabId), tabContextOptionsFromClient(request.options));
        if (!tabContext) {
            throw new Error(`tabContext failed: ${errorReason}`);
        }
        const tabContextResult = tabContextToClient(tabContext, extras);
        return {
            tabContextResult: tabContextResult,
        };
    }
    async createTask(request) {
        try {
            const taskId = await this.actorHandler.createTask(taskOptionsToMojo(request.taskOptions));
            return {
                taskId: taskId,
            };
        }
        catch (errorReason) {
            throw new ErrorWithReasonImpl('createTask', errorReason ??
                CreateTaskErrorReason.UNKNOWN);
        }
    }
    async performActions(request) {
        try {
            const resultProto = await this.actorHandler.performActions(byteArrayFromClient(request.actions));
            const buffer = getArrayBufferFromBigBuffer(resultProto.smuggled);
            if (!buffer) {
                throw PerformActionsErrorReason.UNKNOWN;
            }
            return {
                actionsResult: buffer,
            };
        }
        catch (errorReason) {
            throw new ErrorWithReasonImpl('performActions', errorReason ??
                PerformActionsErrorReason.UNKNOWN);
        }
    }
    async cancelActions(request) {
        const cancelResult = await this.actorHandler.cancelActions(request.taskId);
        return {
            result: enumToClient(cancelResult.result),
        };
    }
    stopActorTask(request) {
        this.actorHandler.stopActorTask(request.taskId, enumFromClient(request.stopReason));
    }
    pauseActorTask(request) {
        this.actorHandler.pauseActorTask(request.taskId, enumFromClient(request.pauseReason), idFromClient(request.tabId));
    }
    async resumeActorTask(request, extras) {
        const { result: { getContextResult, actionResult, }, } = await this.actorHandler.resumeActorTask(request.taskId, tabContextOptionsFromClient(request.tabContextOptions));
        if (!getContextResult.tabContext || actionResult === null) {
            throw new Error(`resumeActorTask failed: ${getContextResult.errorReason}`);
        }
        return {
            resumeActorTaskResult: resumeActorTaskResultToClient(getContextResult.tabContext, actionResult, extras),
        };
    }
    interruptActorTask(request) {
        this.actorHandler.interruptActorTask(request.taskId, enumFromClient(request.interruptReason));
    }
    uninterruptActorTask(request) {
        this.actorHandler.uninterruptActorTask(request.taskId);
    }
    async createActorTab(request) {
        const response = await this.actorHandler.createActorTab(request.taskId, request.options.openInBackground === true, idFromClient(request.options.initiatorTabId), idFromClient(request.options.initiatorWindowId));
        const tabData = response.tabData;
        if (tabData) {
            return {
                tabData: {
                    tabId: idToClient(tabData.tabId),
                    windowId: idToClient(tabData.windowId),
                    url: urlToClient(tabData.url),
                    title: optionalToClient(tabData.title),
                },
            };
        }
        return {};
    }
    logBeginAsyncEvent(request) {
        this.actorHandler.logBeginAsyncEvent(BigInt(request.asyncEventId), request.taskId, request.event, request.details);
    }
    logEndAsyncEvent(request) {
        this.actorHandler.logEndAsyncEvent(BigInt(request.asyncEventId), request.details);
    }
    logInstantEvent(request) {
        this.actorHandler.logInstantEvent(request.taskId, request.event, request.details);
    }
    journalClear() {
        this.actorHandler.journalClear();
    }
    async journalSnapshot(request, extras) {
        const result = await this.actorHandler.journalSnapshot(request.clear);
        const journalArray = new Uint8Array(result.journal.data);
        extras.addTransfer(journalArray.buffer);
        return {
            journal: {
                data: journalArray.buffer,
            },
        };
    }
    journalStart(request) {
        this.actorHandler.journalStart(BigInt(request.maxBytes), request.captureScreenshots);
    }
    journalStop() {
        this.actorHandler.journalStop();
    }
    journalRecordFeedback(request) {
        this.actorHandler.journalRecordFeedback(request.positive, request.reason);
    }
    autofillSuggestionDialogOnFormPresented(payload) {
        this.actorHandler.autofillSuggestionDialogOnFormPresented(payload.taskId, payload.params);
    }
    autofillSuggestionDialogOnFormPreviewChanged(payload) {
        this.actorHandler.autofillSuggestionDialogOnFormPreviewChanged(payload.taskId, {
            formFillingRequestIndex: payload.params.formFillingRequestIndex,
            response: payload.params.response ?? null,
        });
    }
    autofillSuggestionDialogOnFormConfirmed(payload) {
        this.actorHandler.autofillSuggestionDialogOnFormConfirmed(payload.taskId, payload.params);
    }
}
export class ActorClientImpl {
    sender;
    constructor(sender) {
        this.sender = sender;
    }
    notifyActorTaskStateChanged(taskId, state) {
        const clientState = enumToClient(state);
        this.sender.requestNoResponse('notifyActorTaskStateChanged', { taskId, state: clientState });
    }
    async requestToShowCredentialSelectionDialog(request) {
        const clientResponse = await this.sender.requestWithResponse('requestToShowDialog', { request: selectCredentialDialogRequestToClient(request) });
        return {
            response: selectCredentialDialogResponseToMojo(clientResponse.response),
        };
    }
    async requestToShowUserConfirmationDialog(request) {
        const clientResponse = await this.sender.requestWithResponse('requestToShowConfirmationDialog', { request: userConfirmationDialogRequestToClient(request) });
        return {
            response: userConfirmationDialogResponseToMojo(clientResponse.response),
        };
    }
    async requestToConfirmNavigation(request) {
        const clientResponse = await this.sender.requestWithResponse('requestToConfirmNavigation', { request: navigationConfirmationRequestToClient(request) });
        return {
            response: navigationConfirmationResponseToMojo(clientResponse.response),
        };
    }
    async requestToShowAutofillSuggestionsDialog(request) {
        const clientResponse = await this.sender.requestWithResponse('requestToShowAutofillSuggestionsDialog', { request: selectAutofillSuggestionsDialogRequestToClient(request) });
        return {
            response: selectAutofillSuggestionsDialogResponseToMojo(clientResponse.response),
        };
    }
    async requestToShowGmailOtpOptInDialog(taskId) {
        const clientResponse = await this.sender.requestWithResponse('requestToShowGmailOtpOptInDialog', { request: { taskId } });
        return {
            result: gmailOtpOptInResultToMojo(clientResponse.response),
        };
    }
}
assertNever();
assertNever();
assertNever();
function selectCredentialDialogResponseToMojo(response) {
    return response.errorReason ?
        {
            taskId: response.taskId,
            errorReason: response.errorReason,
            permissionDuration: null,
            selectedCredentialId: null,
        } :
        {
            ...response,
            errorReason: null,
            permissionDuration: optionalFromClient(response.permissionDuration),
            selectedCredentialId: response.selectedCredentialId ?? null,
        };
}
function selectCredentialDialogRequestToClient(request) {
    const icons = new Map();
    if (request.icons) {
        for (const [siteOrApp, value] of Object.entries(request.icons)) {
            const rgbaImage = bitmapN32ToRGBAImage(value);
            if (rgbaImage) {
                icons.set(siteOrApp, rgbaImage);
            }
        }
    }
    return {
        ...request,
        credentials: request.credentials.map(credential => ({
            ...credential,
            requestOrigin: originToClient(credential.requestOrigin),
            type: enumToClient(credential.type),
            accountPicture: credential.accountPicture ?
                bitmapN32ToRGBAImage(credential.accountPicture) :
                undefined,
        })),
        icons,
    };
}
function userConfirmationDialogRequestToClient(request) {
    return {
        navigationOrigin: request.payload.navigationOrigin ?
            originToClient(request.payload.navigationOrigin) :
            undefined,
        forBlocklistedOrigin: request.payload.forBlocklistedOrigin,
    };
}
function userConfirmationDialogResponseToMojo(response) {
    if (response.errorReason) {
        return {
            result: {
                errorReason: response.errorReason,
            },
        };
    }
    return {
        result: { permissionGranted: response.permissionGranted },
    };
}
function navigationConfirmationRequestToClient(request) {
    return {
        taskId: request.taskId,
        navigationOrigin: originToClient(request.navigationOrigin),
    };
}
function navigationConfirmationResponseToMojo(response) {
    if (response.errorReason) {
        return {
            result: {
                errorReason: response.errorReason,
            },
        };
    }
    return {
        result: {
            permissionGranted: response.permissionGranted,
        },
    };
}
function selectAutofillSuggestionsDialogRequestToClient(request) {
    return {
        ...request,
        formFillingRequests: request.formFillingRequests.map(r => ({
            ...r,
            requestedData: Number(r.requestedData),
            formattedRequestOrigin: r.formattedRequestOrigin,
            suggestions: r.suggestions.map(s => ({
                ...s,
                icon: s.icon ? bitmapN32ToRGBAImage(s.icon) : undefined,
            })),
        })),
    };
}
function selectAutofillSuggestionsDialogResponseToMojo(response) {
    if (response.errorReason) {
        return {
            taskId: response.taskId,
            result: {
                errorReason: response.errorReason,
            },
        };
    }
    else {
        return {
            taskId: response.taskId,
            result: {
                selectedSuggestions: response.selectedSuggestions,
            },
        };
    }
}
function taskOptionsToMojo(taskOptions) {
    if (taskOptions) {
        return {
            title: taskOptions.title ?? null,
            duration: enumFromClient(taskOptions.duration),
            featureMode: enumFromClient(taskOptions.featureMode ?? FeatureMode.UNSPECIFIED),
        };
    }
    return null;
}
function resumeActorTaskResultToClient(tabContext, actionResult, extras) {
    return {
        ...tabContextToClient(tabContext, extras),
        actionResult,
    };
}
assertNever();
function gmailOtpOptInResultToMojo(response) {
    if (response.errorReason !== undefined) {
        return {
            errorReason: response.errorReason,
        };
    }
    return {
        permissionGranted: response.permissionGranted,
    };
}
