#pragma once

#include <LibHTTP/Cookie/Cookie.h>
#include <LibHTTP/HSTS/ParsedHSTSPolicy.h>
#include <LibIPC/TransportHandle.h>
#include <LibURL/URL.h>
#include <LibWeb/Bindings/AgentType.h>
#include <LibWeb/HTML/BroadcastChannelMessage.h>
#include <LibWeb/HTML/WorkerAgentTypes.h>
#include <AK/Error.h>
#include <AK/MemoryStream.h>
#include <AK/OwnPtr.h>
#include <AK/Platform.h>
#include <AK/Result.h>
#include <AK/Utf8View.h>
#include <LibIPC/Attachment.h>
#include <LibIPC/Connection.h>
#include <LibIPC/Decoder.h>
#include <LibIPC/Encoder.h>
#include <LibIPC/File.h>
#include <LibIPC/Message.h>
#include <LibIPC/Stub.h>

#if defined(AK_COMPILER_CLANG)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdefaulted-function-deleted"
#endif

namespace Messages::WebWorkerClient {

enum class MessageID : i32 {
    DidCloseWorker = 1,
    DidFinishLoadingWorkerScript = 2,
    DidFailLoadingWorkerScript = 3,
    DidReportWorkerException = 4,
    DidRequestCookie = 5,
    DidRequestCookieResponse = 6,
    DidRequestFile = 7,
    DidStoreHstsPolicy = 8,
    DidIsKnownHstsHost = 9,
    DidIsKnownHstsHostResponse = 10,
    DidPostBroadcastChannelMessage = 11,
    StartWorkerAgent = 12,
    StartWorkerAgentResponse = 13,
    CloseWorkerAgent = 14,
};

class DidCloseWorker final : public IPC::Message {
public:
    DidCloseWorker() = default;

    DidCloseWorker(DidCloseWorker const&) = default;
    DidCloseWorker(DidCloseWorker&&) = default;
    DidCloseWorker& operator=(DidCloseWorker const&) = default;

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::DidCloseWorker; }
    static i32 static_message_id() { return (int)MessageID::DidCloseWorker; }
    virtual StringView message_name() const override { return "WebWorkerClient::DidCloseWorker"sv; }

    static ErrorOr<NonnullOwnPtr<DidCloseWorker>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        return make<DidCloseWorker>();
    }

    static ErrorOr<IPC::MessageBuffer> static_encode()
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::DidCloseWorker));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode();
    }

private:
};

class DidFinishLoadingWorkerScript final : public IPC::Message {
public:
    DidFinishLoadingWorkerScript(bool worker_is_secure_context)
        : m_worker_is_secure_context(move(worker_is_secure_context))
    {
    }

    DidFinishLoadingWorkerScript(DidFinishLoadingWorkerScript const&) = default;
    DidFinishLoadingWorkerScript(DidFinishLoadingWorkerScript&&) = default;
    DidFinishLoadingWorkerScript& operator=(DidFinishLoadingWorkerScript const&) = default;

    template<typename WrappedReturnType>
    requires(!SameAs<WrappedReturnType, bool>)
    DidFinishLoadingWorkerScript(WrappedReturnType&& value)
        : m_worker_is_secure_context(forward<WrappedReturnType>(value))
    {
    }

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::DidFinishLoadingWorkerScript; }
    static i32 static_message_id() { return (int)MessageID::DidFinishLoadingWorkerScript; }
    virtual StringView message_name() const override { return "WebWorkerClient::DidFinishLoadingWorkerScript"sv; }

    static ErrorOr<NonnullOwnPtr<DidFinishLoadingWorkerScript>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto worker_is_secure_context = TRY((decoder.decode<bool>()));
        return make<DidFinishLoadingWorkerScript>(move(worker_is_secure_context));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(bool worker_is_secure_context)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::DidFinishLoadingWorkerScript));
        TRY(stream.encode(worker_is_secure_context));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_worker_is_secure_context);
    }

    bool worker_is_secure_context() const { return m_worker_is_secure_context; }

private:
    bool m_worker_is_secure_context;
};

class DidFailLoadingWorkerScript final : public IPC::Message {
public:
    DidFailLoadingWorkerScript() = default;

    DidFailLoadingWorkerScript(DidFailLoadingWorkerScript const&) = default;
    DidFailLoadingWorkerScript(DidFailLoadingWorkerScript&&) = default;
    DidFailLoadingWorkerScript& operator=(DidFailLoadingWorkerScript const&) = default;

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::DidFailLoadingWorkerScript; }
    static i32 static_message_id() { return (int)MessageID::DidFailLoadingWorkerScript; }
    virtual StringView message_name() const override { return "WebWorkerClient::DidFailLoadingWorkerScript"sv; }

    static ErrorOr<NonnullOwnPtr<DidFailLoadingWorkerScript>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        return make<DidFailLoadingWorkerScript>();
    }

    static ErrorOr<IPC::MessageBuffer> static_encode()
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::DidFailLoadingWorkerScript));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode();
    }

private:
};

class DidReportWorkerException final : public IPC::Message {
public:
    DidReportWorkerException(String message, String filename, u32 lineno, u32 colno)
        : m_message(move(message))
        , m_filename(move(filename))
        , m_lineno(move(lineno))
        , m_colno(move(colno))
    {
    }

    DidReportWorkerException(DidReportWorkerException const&) = default;
    DidReportWorkerException(DidReportWorkerException&&) = default;
    DidReportWorkerException& operator=(DidReportWorkerException const&) = default;

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::DidReportWorkerException; }
    static i32 static_message_id() { return (int)MessageID::DidReportWorkerException; }
    virtual StringView message_name() const override { return "WebWorkerClient::DidReportWorkerException"sv; }

    static ErrorOr<NonnullOwnPtr<DidReportWorkerException>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto message = TRY((decoder.decode<String>()));
        auto filename = TRY((decoder.decode<String>()));
        auto lineno = TRY((decoder.decode<u32>()));
        auto colno = TRY((decoder.decode<u32>()));
        return make<DidReportWorkerException>(move(message), move(filename), move(lineno), move(colno));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(StringView message, StringView filename, u32 lineno, u32 colno)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::DidReportWorkerException));
        TRY(stream.encode(message));
        TRY(stream.encode(filename));
        TRY(stream.encode(lineno));
        TRY(stream.encode(colno));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_message, m_filename, m_lineno, m_colno);
    }

    String const& message() const { return m_message; }
    String take_message() { return move(m_message); }

    String const& filename() const { return m_filename; }
    String take_filename() { return move(m_filename); }

    u32 lineno() const { return m_lineno; }

    u32 colno() const { return m_colno; }

private:
    String m_message;
    String m_filename;
    u32 m_lineno;
    u32 m_colno;
};

class DidRequestCookieResponse final : public IPC::Message {
public:
    DidRequestCookieResponse(HTTP::Cookie::VersionedCookie cookie)
        : m_cookie(move(cookie))
    {
    }

    DidRequestCookieResponse(DidRequestCookieResponse const&) = default;
    DidRequestCookieResponse(DidRequestCookieResponse&&) = default;
    DidRequestCookieResponse& operator=(DidRequestCookieResponse const&) = default;

    template<typename WrappedReturnType>
    requires(!SameAs<WrappedReturnType, HTTP::Cookie::VersionedCookie>)
    DidRequestCookieResponse(WrappedReturnType&& value)
        : m_cookie(forward<WrappedReturnType>(value))
    {
    }

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::DidRequestCookieResponse; }
    static i32 static_message_id() { return (int)MessageID::DidRequestCookieResponse; }
    virtual StringView message_name() const override { return "WebWorkerClient::DidRequestCookieResponse"sv; }

    static ErrorOr<NonnullOwnPtr<DidRequestCookieResponse>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto cookie = TRY((decoder.decode<HTTP::Cookie::VersionedCookie>()));
        return make<DidRequestCookieResponse>(move(cookie));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(HTTP::Cookie::VersionedCookie const& cookie)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::DidRequestCookieResponse));
        TRY(stream.encode(cookie));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_cookie);
    }

    HTTP::Cookie::VersionedCookie const& cookie() const { return m_cookie; }
    HTTP::Cookie::VersionedCookie take_cookie() { return move(m_cookie); }

private:
    HTTP::Cookie::VersionedCookie m_cookie;
};

class DidRequestCookie final : public IPC::Message {
public:
    typedef class DidRequestCookieResponse ResponseType;

    DidRequestCookie(URL::URL url, HTTP::Cookie::Source source)
        : m_url(move(url))
        , m_source(move(source))
    {
    }

    DidRequestCookie(DidRequestCookie const&) = default;
    DidRequestCookie(DidRequestCookie&&) = default;
    DidRequestCookie& operator=(DidRequestCookie const&) = default;

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::DidRequestCookie; }
    static i32 static_message_id() { return (int)MessageID::DidRequestCookie; }
    virtual StringView message_name() const override { return "WebWorkerClient::DidRequestCookie"sv; }

    static ErrorOr<NonnullOwnPtr<DidRequestCookie>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto url = TRY((decoder.decode<URL::URL>()));
        auto source = TRY((decoder.decode<HTTP::Cookie::Source>()));
        return make<DidRequestCookie>(move(url), move(source));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(URL::URL const& url, HTTP::Cookie::Source source)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::DidRequestCookie));
        TRY(stream.encode(url));
        TRY(stream.encode(source));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_url, m_source);
    }

    URL::URL const& url() const { return m_url; }
    URL::URL take_url() { return move(m_url); }

    HTTP::Cookie::Source source() const { return m_source; }

private:
    URL::URL m_url;
    HTTP::Cookie::Source m_source;
};

class DidRequestFile final : public IPC::Message {
public:
    DidRequestFile(ByteString path, i32 request_id)
        : m_path(move(path))
        , m_request_id(move(request_id))
    {
    }

    DidRequestFile(DidRequestFile const&) = default;
    DidRequestFile(DidRequestFile&&) = default;
    DidRequestFile& operator=(DidRequestFile const&) = default;

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::DidRequestFile; }
    static i32 static_message_id() { return (int)MessageID::DidRequestFile; }
    virtual StringView message_name() const override { return "WebWorkerClient::DidRequestFile"sv; }

    static ErrorOr<NonnullOwnPtr<DidRequestFile>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto path = TRY((decoder.decode<ByteString>()));
        auto request_id = TRY((decoder.decode<i32>()));
        return make<DidRequestFile>(move(path), move(request_id));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(StringView path, i32 request_id)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::DidRequestFile));
        TRY(stream.encode(path));
        TRY(stream.encode(request_id));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_path, m_request_id);
    }

    ByteString const& path() const { return m_path; }
    ByteString take_path() { return move(m_path); }

    i32 request_id() const { return m_request_id; }

private:
    ByteString m_path;
    i32 m_request_id;
};

class DidStoreHstsPolicy final : public IPC::Message {
public:
    DidStoreHstsPolicy(String domain, HTTP::HSTS::ParsedHSTSPolicy policy)
        : m_domain(move(domain))
        , m_policy(move(policy))
    {
    }

    DidStoreHstsPolicy(DidStoreHstsPolicy const&) = default;
    DidStoreHstsPolicy(DidStoreHstsPolicy&&) = default;
    DidStoreHstsPolicy& operator=(DidStoreHstsPolicy const&) = default;

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::DidStoreHstsPolicy; }
    static i32 static_message_id() { return (int)MessageID::DidStoreHstsPolicy; }
    virtual StringView message_name() const override { return "WebWorkerClient::DidStoreHstsPolicy"sv; }

    static ErrorOr<NonnullOwnPtr<DidStoreHstsPolicy>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto domain = TRY((decoder.decode<String>()));
        auto policy = TRY((decoder.decode<HTTP::HSTS::ParsedHSTSPolicy>()));
        return make<DidStoreHstsPolicy>(move(domain), move(policy));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(StringView domain, HTTP::HSTS::ParsedHSTSPolicy const& policy)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::DidStoreHstsPolicy));
        TRY(stream.encode(domain));
        TRY(stream.encode(policy));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_domain, m_policy);
    }

    String const& domain() const { return m_domain; }
    String take_domain() { return move(m_domain); }

    HTTP::HSTS::ParsedHSTSPolicy const& policy() const { return m_policy; }
    HTTP::HSTS::ParsedHSTSPolicy take_policy() { return move(m_policy); }

private:
    String m_domain;
    HTTP::HSTS::ParsedHSTSPolicy m_policy;
};

class DidIsKnownHstsHostResponse final : public IPC::Message {
public:
    DidIsKnownHstsHostResponse(bool result)
        : m_result(move(result))
    {
    }

    DidIsKnownHstsHostResponse(DidIsKnownHstsHostResponse const&) = default;
    DidIsKnownHstsHostResponse(DidIsKnownHstsHostResponse&&) = default;
    DidIsKnownHstsHostResponse& operator=(DidIsKnownHstsHostResponse const&) = default;

    template<typename WrappedReturnType>
    requires(!SameAs<WrappedReturnType, bool>)
    DidIsKnownHstsHostResponse(WrappedReturnType&& value)
        : m_result(forward<WrappedReturnType>(value))
    {
    }

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::DidIsKnownHstsHostResponse; }
    static i32 static_message_id() { return (int)MessageID::DidIsKnownHstsHostResponse; }
    virtual StringView message_name() const override { return "WebWorkerClient::DidIsKnownHstsHostResponse"sv; }

    static ErrorOr<NonnullOwnPtr<DidIsKnownHstsHostResponse>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto result = TRY((decoder.decode<bool>()));
        return make<DidIsKnownHstsHostResponse>(move(result));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(bool result)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::DidIsKnownHstsHostResponse));
        TRY(stream.encode(result));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_result);
    }

    bool result() const { return m_result; }

private:
    bool m_result;
};

class DidIsKnownHstsHost final : public IPC::Message {
public:
    typedef class DidIsKnownHstsHostResponse ResponseType;

    DidIsKnownHstsHost(String domain)
        : m_domain(move(domain))
    {
    }

    DidIsKnownHstsHost(DidIsKnownHstsHost const&) = default;
    DidIsKnownHstsHost(DidIsKnownHstsHost&&) = default;
    DidIsKnownHstsHost& operator=(DidIsKnownHstsHost const&) = default;

    template<typename WrappedReturnType>
    requires(!SameAs<WrappedReturnType, String>)
    DidIsKnownHstsHost(WrappedReturnType&& value)
        : m_domain(forward<WrappedReturnType>(value))
    {
    }

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::DidIsKnownHstsHost; }
    static i32 static_message_id() { return (int)MessageID::DidIsKnownHstsHost; }
    virtual StringView message_name() const override { return "WebWorkerClient::DidIsKnownHstsHost"sv; }

    static ErrorOr<NonnullOwnPtr<DidIsKnownHstsHost>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto domain = TRY((decoder.decode<String>()));
        return make<DidIsKnownHstsHost>(move(domain));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(StringView domain)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::DidIsKnownHstsHost));
        TRY(stream.encode(domain));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_domain);
    }

    String const& domain() const { return m_domain; }
    String take_domain() { return move(m_domain); }

private:
    String m_domain;
};

class DidPostBroadcastChannelMessage final : public IPC::Message {
public:
    DidPostBroadcastChannelMessage(Web::HTML::BroadcastChannelMessage message)
        : m_message(move(message))
    {
    }

    DidPostBroadcastChannelMessage(DidPostBroadcastChannelMessage const&) = default;
    DidPostBroadcastChannelMessage(DidPostBroadcastChannelMessage&&) = default;
    DidPostBroadcastChannelMessage& operator=(DidPostBroadcastChannelMessage const&) = default;

    template<typename WrappedReturnType>
    requires(!SameAs<WrappedReturnType, Web::HTML::BroadcastChannelMessage>)
    DidPostBroadcastChannelMessage(WrappedReturnType&& value)
        : m_message(forward<WrappedReturnType>(value))
    {
    }

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::DidPostBroadcastChannelMessage; }
    static i32 static_message_id() { return (int)MessageID::DidPostBroadcastChannelMessage; }
    virtual StringView message_name() const override { return "WebWorkerClient::DidPostBroadcastChannelMessage"sv; }

    static ErrorOr<NonnullOwnPtr<DidPostBroadcastChannelMessage>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto message = TRY((decoder.decode<Web::HTML::BroadcastChannelMessage>()));
        return make<DidPostBroadcastChannelMessage>(move(message));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(Web::HTML::BroadcastChannelMessage const& message)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::DidPostBroadcastChannelMessage));
        TRY(stream.encode(message));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_message);
    }

    Web::HTML::BroadcastChannelMessage const& message() const { return m_message; }
    Web::HTML::BroadcastChannelMessage take_message() { return move(m_message); }

private:
    Web::HTML::BroadcastChannelMessage m_message;
};

class StartWorkerAgentResponse final : public IPC::Message {
public:
    StartWorkerAgentResponse(Web::HTML::WorkerAgentId agent_id)
        : m_agent_id(move(agent_id))
    {
    }

    StartWorkerAgentResponse(StartWorkerAgentResponse const&) = default;
    StartWorkerAgentResponse(StartWorkerAgentResponse&&) = default;
    StartWorkerAgentResponse& operator=(StartWorkerAgentResponse const&) = default;

    template<typename WrappedReturnType>
    requires(!SameAs<WrappedReturnType, Web::HTML::WorkerAgentId>)
    StartWorkerAgentResponse(WrappedReturnType&& value)
        : m_agent_id(forward<WrappedReturnType>(value))
    {
    }

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::StartWorkerAgentResponse; }
    static i32 static_message_id() { return (int)MessageID::StartWorkerAgentResponse; }
    virtual StringView message_name() const override { return "WebWorkerClient::StartWorkerAgentResponse"sv; }

    static ErrorOr<NonnullOwnPtr<StartWorkerAgentResponse>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto agent_id = TRY((decoder.decode<Web::HTML::WorkerAgentId>()));
        return make<StartWorkerAgentResponse>(move(agent_id));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(Web::HTML::WorkerAgentId const& agent_id)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::StartWorkerAgentResponse));
        TRY(stream.encode(agent_id));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_agent_id);
    }

    Web::HTML::WorkerAgentId const& agent_id() const { return m_agent_id; }
    Web::HTML::WorkerAgentId take_agent_id() { return move(m_agent_id); }

private:
    Web::HTML::WorkerAgentId m_agent_id;
};

class StartWorkerAgent final : public IPC::Message {
public:
    typedef class StartWorkerAgentResponse ResponseType;

    StartWorkerAgent(Web::HTML::WorkerAgentStartRequest request)
        : m_request(move(request))
    {
    }

    StartWorkerAgent(StartWorkerAgent const&) = default;
    StartWorkerAgent(StartWorkerAgent&&) = default;
    StartWorkerAgent& operator=(StartWorkerAgent const&) = default;

    template<typename WrappedReturnType>
    requires(!SameAs<WrappedReturnType, Web::HTML::WorkerAgentStartRequest>)
    StartWorkerAgent(WrappedReturnType&& value)
        : m_request(forward<WrappedReturnType>(value))
    {
    }

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::StartWorkerAgent; }
    static i32 static_message_id() { return (int)MessageID::StartWorkerAgent; }
    virtual StringView message_name() const override { return "WebWorkerClient::StartWorkerAgent"sv; }

    static ErrorOr<NonnullOwnPtr<StartWorkerAgent>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto request = TRY((decoder.decode<Web::HTML::WorkerAgentStartRequest>()));
        return make<StartWorkerAgent>(move(request));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(Web::HTML::WorkerAgentStartRequest const& request)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::StartWorkerAgent));
        TRY(stream.encode(request));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_request);
    }

    Web::HTML::WorkerAgentStartRequest const& request() const { return m_request; }
    Web::HTML::WorkerAgentStartRequest take_request() { return move(m_request); }

private:
    Web::HTML::WorkerAgentStartRequest m_request;
};

class CloseWorkerAgent final : public IPC::Message {
public:
    CloseWorkerAgent(Web::HTML::WorkerAgentId agent_id, Web::HTML::WorkerAgentOwnerToken owner_token)
        : m_agent_id(move(agent_id))
        , m_owner_token(move(owner_token))
    {
    }

    CloseWorkerAgent(CloseWorkerAgent const&) = default;
    CloseWorkerAgent(CloseWorkerAgent&&) = default;
    CloseWorkerAgent& operator=(CloseWorkerAgent const&) = default;

    static constexpr u32 ENDPOINT_MAGIC = 1974781266;

    virtual u32 endpoint_magic() const override { return ENDPOINT_MAGIC; }
    virtual i32 message_id() const override { return (int)MessageID::CloseWorkerAgent; }
    static i32 static_message_id() { return (int)MessageID::CloseWorkerAgent; }
    virtual StringView message_name() const override { return "WebWorkerClient::CloseWorkerAgent"sv; }

    static ErrorOr<NonnullOwnPtr<CloseWorkerAgent>> decode(Stream& stream, Queue<IPC::Attachment>& attachments)
    {
        IPC::Decoder decoder { stream, attachments };
        auto agent_id = TRY((decoder.decode<Web::HTML::WorkerAgentId>()));
        auto owner_token = TRY((decoder.decode<Web::HTML::WorkerAgentOwnerToken>()));
        return make<CloseWorkerAgent>(move(agent_id), move(owner_token));
    }

    static ErrorOr<IPC::MessageBuffer> static_encode(Web::HTML::WorkerAgentId const& agent_id, Web::HTML::WorkerAgentOwnerToken const& owner_token)
    {
        IPC::MessageBuffer buffer;
        IPC::Encoder stream(buffer);
        TRY(stream.encode(ENDPOINT_MAGIC));
        TRY(stream.encode((int)MessageID::CloseWorkerAgent));
        TRY(stream.encode(agent_id));
        TRY(stream.encode(owner_token));
        return buffer;
    }

    virtual ErrorOr<IPC::MessageBuffer> encode() const override
    {
        return static_encode(m_agent_id, m_owner_token);
    }

    Web::HTML::WorkerAgentId const& agent_id() const { return m_agent_id; }
    Web::HTML::WorkerAgentId take_agent_id() { return move(m_agent_id); }

    Web::HTML::WorkerAgentOwnerToken const& owner_token() const { return m_owner_token; }
    Web::HTML::WorkerAgentOwnerToken take_owner_token() { return move(m_owner_token); }

private:
    Web::HTML::WorkerAgentId m_agent_id;
    Web::HTML::WorkerAgentOwnerToken m_owner_token;
};

} // namespace Messages::WebWorkerClient

template<typename LocalEndpoint, typename PeerEndpoint>
class WebWorkerClientProxy {
public:
    // Used to disambiguate the constructor call.
    struct Tag { };

    WebWorkerClientProxy(IPC::Connection<LocalEndpoint, PeerEndpoint>& connection, Tag)
        : m_connection(connection)
    {
    }

    void async_did_close_worker()
    {
        auto message_buffer = MUST(Messages::WebWorkerClient::DidCloseWorker::static_encode());
        (void)m_connection.post_message(message_buffer);
    }

    void async_did_finish_loading_worker_script(bool worker_is_secure_context)
    {
        auto message_buffer = MUST(Messages::WebWorkerClient::DidFinishLoadingWorkerScript::static_encode(worker_is_secure_context));
        (void)m_connection.post_message(message_buffer);
    }

    void async_did_fail_loading_worker_script()
    {
        auto message_buffer = MUST(Messages::WebWorkerClient::DidFailLoadingWorkerScript::static_encode());
        (void)m_connection.post_message(message_buffer);
    }

    void async_did_report_worker_exception(StringView message, StringView filename, u32 lineno, u32 colno)
    {
        VERIFY(Utf8View { message }.validate());
        VERIFY(Utf8View { filename }.validate());
        auto message_buffer = MUST(Messages::WebWorkerClient::DidReportWorkerException::static_encode(message, filename, lineno, colno));
        (void)m_connection.post_message(message_buffer);
    }

    void async_did_report_worker_exception(String const& message, String const& filename, u32 lineno, u32 colno)
    {
        auto message_buffer = MUST(Messages::WebWorkerClient::DidReportWorkerException::static_encode(message, filename, lineno, colno));
        (void)m_connection.post_message(message_buffer);
    }

    HTTP::Cookie::VersionedCookie did_request_cookie(URL::URL url, HTTP::Cookie::Source source)
    {
        return m_connection.template send_sync<Messages::WebWorkerClient::DidRequestCookie>(move(url), source)->take_cookie();
    }

    void async_did_request_cookie(URL::URL const& url, HTTP::Cookie::Source source)
    {
        auto message_buffer = MUST(Messages::WebWorkerClient::DidRequestCookie::static_encode(move(url), source));
        (void)m_connection.post_message(message_buffer);
    }

    IPC::IPCErrorOr<HTTP::Cookie::VersionedCookie> try_did_request_cookie(URL::URL url, HTTP::Cookie::Source source)
    {
        if (auto result = m_connection.template send_sync_but_allow_failure<Messages::WebWorkerClient::DidRequestCookie>(move(url), source))
            return result->take_cookie();
        m_connection.shutdown();
        return IPC::ErrorCode::PeerDisconnected;
    }

    void async_did_request_file(StringView path, i32 request_id)
    {
        auto message_buffer = MUST(Messages::WebWorkerClient::DidRequestFile::static_encode(path, request_id));
        (void)m_connection.post_message(message_buffer);
    }

    void async_did_store_hsts_policy(StringView domain, HTTP::HSTS::ParsedHSTSPolicy const& policy)
    {
        VERIFY(Utf8View { domain }.validate());
        auto message_buffer = MUST(Messages::WebWorkerClient::DidStoreHstsPolicy::static_encode(domain, move(policy)));
        (void)m_connection.post_message(message_buffer);
    }

    void async_did_store_hsts_policy(String const& domain, HTTP::HSTS::ParsedHSTSPolicy const& policy)
    {
        auto message_buffer = MUST(Messages::WebWorkerClient::DidStoreHstsPolicy::static_encode(domain, move(policy)));
        (void)m_connection.post_message(message_buffer);
    }

    bool did_is_known_hsts_host(String domain)
    {
        return m_connection.template send_sync<Messages::WebWorkerClient::DidIsKnownHstsHost>(move(domain))->result();
    }

    void async_did_is_known_hsts_host(StringView domain)
    {
        VERIFY(Utf8View { domain }.validate());
        auto message_buffer = MUST(Messages::WebWorkerClient::DidIsKnownHstsHost::static_encode(domain));
        (void)m_connection.post_message(message_buffer);
    }

    void async_did_is_known_hsts_host(String const& domain)
    {
        auto message_buffer = MUST(Messages::WebWorkerClient::DidIsKnownHstsHost::static_encode(domain));
        (void)m_connection.post_message(message_buffer);
    }

    IPC::IPCErrorOr<bool> try_did_is_known_hsts_host(String domain)
    {
        if (auto result = m_connection.template send_sync_but_allow_failure<Messages::WebWorkerClient::DidIsKnownHstsHost>(move(domain)))
            return result->result();
        m_connection.shutdown();
        return IPC::ErrorCode::PeerDisconnected;
    }

    void async_did_post_broadcast_channel_message(Web::HTML::BroadcastChannelMessage const& message)
    {
        auto message_buffer = MUST(Messages::WebWorkerClient::DidPostBroadcastChannelMessage::static_encode(move(message)));
        (void)m_connection.post_message(message_buffer);
    }

    Web::HTML::WorkerAgentId start_worker_agent(Web::HTML::WorkerAgentStartRequest request)
    {
        return m_connection.template send_sync<Messages::WebWorkerClient::StartWorkerAgent>(move(request))->take_agent_id();
    }

    void async_start_worker_agent(Web::HTML::WorkerAgentStartRequest const& request)
    {
        auto message_buffer = MUST(Messages::WebWorkerClient::StartWorkerAgent::static_encode(move(request)));
        (void)m_connection.post_message(message_buffer);
    }

    IPC::IPCErrorOr<Web::HTML::WorkerAgentId> try_start_worker_agent(Web::HTML::WorkerAgentStartRequest request)
    {
        if (auto result = m_connection.template send_sync_but_allow_failure<Messages::WebWorkerClient::StartWorkerAgent>(move(request)))
            return result->take_agent_id();
        m_connection.shutdown();
        return IPC::ErrorCode::PeerDisconnected;
    }

    void async_close_worker_agent(Web::HTML::WorkerAgentId const& agent_id, Web::HTML::WorkerAgentOwnerToken const& owner_token)
    {
        auto message_buffer = MUST(Messages::WebWorkerClient::CloseWorkerAgent::static_encode(move(agent_id), move(owner_token)));
        (void)m_connection.post_message(message_buffer);
    }

private:
    IPC::Connection<LocalEndpoint, PeerEndpoint>& m_connection;
};

template<typename LocalEndpoint, typename PeerEndpoint>
class WebWorkerClientProxy;
class WebWorkerClientStub;

class WebWorkerClientEndpoint {
public:
    template<typename LocalEndpoint>
    using Proxy = WebWorkerClientProxy<LocalEndpoint, WebWorkerClientEndpoint>;
    using Stub = WebWorkerClientStub;

    static u32 static_magic() { return 1974781266; }

    static ErrorOr<NonnullOwnPtr<IPC::Message>> decode_message(ReadonlyBytes buffer, [[maybe_unused]] Queue<IPC::Attachment>& attachments)
    {
        FixedMemoryStream stream { buffer };
        auto message_endpoint_magic = TRY(stream.read_value<u32>());

        if (message_endpoint_magic != static_magic())
            return Error::from_string_literal("Endpoint magic number mismatch, not my message!");

        auto message_id = TRY(stream.read_value<i32>());

        switch (message_id) {
        case (int)Messages::WebWorkerClient::MessageID::DidCloseWorker:
            return Messages::WebWorkerClient::DidCloseWorker::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::DidFinishLoadingWorkerScript:
            return Messages::WebWorkerClient::DidFinishLoadingWorkerScript::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::DidFailLoadingWorkerScript:
            return Messages::WebWorkerClient::DidFailLoadingWorkerScript::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::DidReportWorkerException:
            return Messages::WebWorkerClient::DidReportWorkerException::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::DidRequestCookie:
            return Messages::WebWorkerClient::DidRequestCookie::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::DidRequestCookieResponse:
            return Messages::WebWorkerClient::DidRequestCookieResponse::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::DidRequestFile:
            return Messages::WebWorkerClient::DidRequestFile::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::DidStoreHstsPolicy:
            return Messages::WebWorkerClient::DidStoreHstsPolicy::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::DidIsKnownHstsHost:
            return Messages::WebWorkerClient::DidIsKnownHstsHost::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::DidIsKnownHstsHostResponse:
            return Messages::WebWorkerClient::DidIsKnownHstsHostResponse::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::DidPostBroadcastChannelMessage:
            return Messages::WebWorkerClient::DidPostBroadcastChannelMessage::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::StartWorkerAgent:
            return Messages::WebWorkerClient::StartWorkerAgent::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::StartWorkerAgentResponse:
            return Messages::WebWorkerClient::StartWorkerAgentResponse::decode(stream, attachments);
        case (int)Messages::WebWorkerClient::MessageID::CloseWorkerAgent:
            return Messages::WebWorkerClient::CloseWorkerAgent::decode(stream, attachments);
        default:
            return Error::from_string_literal("Failed to decode WebWorkerClient message");
        }

        VERIFY_NOT_REACHED();
    }
};

class WebWorkerClientStub : public IPC::Stub {
public:
    WebWorkerClientStub() { }
    virtual ~WebWorkerClientStub() override { }

    virtual u32 magic() const override { return 1974781266; }
    virtual ByteString name() const override { return "WebWorkerClient"; }

    virtual ErrorOr<OwnPtr<IPC::MessageBuffer>> handle(NonnullOwnPtr<IPC::Message> message) override
    {
        switch (message->message_id()) {
        case (int)Messages::WebWorkerClient::MessageID::DidCloseWorker:
            return handle_did_close_worker();
        case (int)Messages::WebWorkerClient::MessageID::DidFinishLoadingWorkerScript:
            return handle_did_finish_loading_worker_script(*message);
        case (int)Messages::WebWorkerClient::MessageID::DidFailLoadingWorkerScript:
            return handle_did_fail_loading_worker_script();
        case (int)Messages::WebWorkerClient::MessageID::DidReportWorkerException:
            return handle_did_report_worker_exception(*message);
        case (int)Messages::WebWorkerClient::MessageID::DidRequestCookie:
            return handle_did_request_cookie(*message);
        case (int)Messages::WebWorkerClient::MessageID::DidRequestFile:
            return handle_did_request_file(*message);
        case (int)Messages::WebWorkerClient::MessageID::DidStoreHstsPolicy:
            return handle_did_store_hsts_policy(*message);
        case (int)Messages::WebWorkerClient::MessageID::DidIsKnownHstsHost:
            return handle_did_is_known_hsts_host(*message);
        case (int)Messages::WebWorkerClient::MessageID::DidPostBroadcastChannelMessage:
            return handle_did_post_broadcast_channel_message(*message);
        case (int)Messages::WebWorkerClient::MessageID::StartWorkerAgent:
            return handle_start_worker_agent(*message);
        case (int)Messages::WebWorkerClient::MessageID::CloseWorkerAgent:
            return handle_close_worker_agent(*message);
        default:
            return Error::from_string_literal("Unknown message ID for WebWorkerClient endpoint");
        }
    }

    NEVER_INLINE ErrorOr<OwnPtr<IPC::MessageBuffer>> handle_did_close_worker()
    {
        did_close_worker();
        return nullptr;
    }

    NEVER_INLINE ErrorOr<OwnPtr<IPC::MessageBuffer>> handle_did_finish_loading_worker_script(IPC::Message& message)
    {
        auto& request = static_cast<Messages::WebWorkerClient::DidFinishLoadingWorkerScript&>(message);
        did_finish_loading_worker_script(request.worker_is_secure_context());
        return nullptr;
    }

    NEVER_INLINE ErrorOr<OwnPtr<IPC::MessageBuffer>> handle_did_fail_loading_worker_script()
    {
        did_fail_loading_worker_script();
        return nullptr;
    }

    NEVER_INLINE ErrorOr<OwnPtr<IPC::MessageBuffer>> handle_did_report_worker_exception(IPC::Message& message)
    {
        auto& request = static_cast<Messages::WebWorkerClient::DidReportWorkerException&>(message);
        did_report_worker_exception(request.take_message(), request.take_filename(), request.lineno(), request.colno());
        return nullptr;
    }

    NEVER_INLINE ErrorOr<OwnPtr<IPC::MessageBuffer>> handle_did_request_cookie(IPC::Message& message)
    {
        auto& request = static_cast<Messages::WebWorkerClient::DidRequestCookie&>(message);
        auto response = did_request_cookie(request.take_url(), request.source());
        return make<IPC::MessageBuffer>(TRY(response.encode()));
    }

    NEVER_INLINE ErrorOr<OwnPtr<IPC::MessageBuffer>> handle_did_request_file(IPC::Message& message)
    {
        auto& request = static_cast<Messages::WebWorkerClient::DidRequestFile&>(message);
        did_request_file(request.take_path(), request.request_id());
        return nullptr;
    }

    NEVER_INLINE ErrorOr<OwnPtr<IPC::MessageBuffer>> handle_did_store_hsts_policy(IPC::Message& message)
    {
        auto& request = static_cast<Messages::WebWorkerClient::DidStoreHstsPolicy&>(message);
        did_store_hsts_policy(request.take_domain(), request.take_policy());
        return nullptr;
    }

    NEVER_INLINE ErrorOr<OwnPtr<IPC::MessageBuffer>> handle_did_is_known_hsts_host(IPC::Message& message)
    {
        auto& request = static_cast<Messages::WebWorkerClient::DidIsKnownHstsHost&>(message);
        auto response = did_is_known_hsts_host(request.take_domain());
        return make<IPC::MessageBuffer>(TRY(response.encode()));
    }

    NEVER_INLINE ErrorOr<OwnPtr<IPC::MessageBuffer>> handle_did_post_broadcast_channel_message(IPC::Message& message)
    {
        auto& request = static_cast<Messages::WebWorkerClient::DidPostBroadcastChannelMessage&>(message);
        did_post_broadcast_channel_message(request.take_message());
        return nullptr;
    }

    NEVER_INLINE ErrorOr<OwnPtr<IPC::MessageBuffer>> handle_start_worker_agent(IPC::Message& message)
    {
        auto& request = static_cast<Messages::WebWorkerClient::StartWorkerAgent&>(message);
        auto response = start_worker_agent(request.take_request());
        return make<IPC::MessageBuffer>(TRY(response.encode()));
    }

    NEVER_INLINE ErrorOr<OwnPtr<IPC::MessageBuffer>> handle_close_worker_agent(IPC::Message& message)
    {
        auto& request = static_cast<Messages::WebWorkerClient::CloseWorkerAgent&>(message);
        close_worker_agent(request.take_agent_id(), request.take_owner_token());
        return nullptr;
    }

    virtual void did_close_worker() = 0;
    virtual void did_finish_loading_worker_script(bool worker_is_secure_context) = 0;
    virtual void did_fail_loading_worker_script() = 0;
    virtual void did_report_worker_exception(String message, String filename, u32 lineno, u32 colno) = 0;
    virtual Messages::WebWorkerClient::DidRequestCookieResponse did_request_cookie(URL::URL url, HTTP::Cookie::Source source) = 0;
    virtual void did_request_file(ByteString path, i32 request_id) = 0;
    virtual void did_store_hsts_policy(String domain, HTTP::HSTS::ParsedHSTSPolicy policy) = 0;
    virtual Messages::WebWorkerClient::DidIsKnownHstsHostResponse did_is_known_hsts_host(String domain) = 0;
    virtual void did_post_broadcast_channel_message(Web::HTML::BroadcastChannelMessage message) = 0;
    virtual Messages::WebWorkerClient::StartWorkerAgentResponse start_worker_agent(Web::HTML::WorkerAgentStartRequest request) = 0;
    virtual void close_worker_agent(Web::HTML::WorkerAgentId agent_id, Web::HTML::WorkerAgentOwnerToken owner_token) = 0;
};

#if defined(AK_COMPILER_CLANG)
#pragma clang diagnostic pop
#endif
