/*
 * Copyright (C) 2019 Sony Interactive Entertainment Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "SessionHost.h"
#include <wtf/UUID.h>

namespace WebDriver {

SessionHost::~SessionHost()
{
}

HashMap<String, Inspector::RemoteInspectorConnectionClient::CallHandler>& SessionHost::dispatchMap()
{
    static NeverDestroyed<HashMap<String, CallHandler>> methods = HashMap<String, CallHandler>({
        {"SetTargetList"_s, static_cast<CallHandler>(&SessionHost::receivedSetTargetList)},
        {"SendMessageToFrontend"_s, static_cast<CallHandler>(&SessionHost::receivedSendMessageToFrontend)},
        {"StartAutomationSession_Return"_s, static_cast<CallHandler>(&SessionHost::receivedStartAutomationSessionReturn)},
    });

    return methods;
}

void SessionHost::sendWebInspectorEvent(const String& event)
{
    if (!m_clientID)
        return;

    const CString message = event.utf8();
    send(m_clientID.value(), message.dataAsUInt8Ptr(), message.length());
}

void SessionHost::connectToBrowser(Function<void (std::optional<String> error)>&& completionHandler)
{
    String targetIp;
    uint16_t targetPort = 0;

    if (!m_targetIp.isEmpty() && m_targetPort) {
        targetIp = m_targetIp;
        targetPort = m_targetPort;
    } else if (m_capabilities.targetAddr && m_capabilities.targetPort) {
        targetIp = m_capabilities.targetAddr.value();
        targetPort = m_capabilities.targetPort.value();
    }

    if (targetIp.isEmpty() || !targetPort) {
        completionHandler(makeString("Target IP/port is invalid, or not specified."));
        return;
    }

    m_clientID = connectInet(targetIp.utf8().data(), targetPort);
    if (!m_clientID)
        completionHandler(makeString(targetIp.utf8().data(), ":", String::number(targetPort), " is not reachable."));
    else
        completionHandler(std::nullopt);
}

bool SessionHost::isConnected() const
{
    return m_clientID.has_value();
}

void SessionHost::didClose(Inspector::RemoteInspectorSocketEndpoint&, Inspector::ConnectionID)
{
    inspectorDisconnected();

    m_clientID = std::nullopt;
}

std::optional<Vector<SessionHost::Target>> SessionHost::parseTargetList(const struct Event& event)
{
    auto result = parseTargetListJSON(*event.message);
    if (!result)
        return std::nullopt;

    Vector<SessionHost::Target> targetList;
    for (const auto& itemObject : *result) {
        SessionHost::Target target;
        String name;
        String type;
        auto targetId = itemObject->getInteger("targetID"_s);
        if (!targetId
            || !itemObject->getString("name"_s, name)
            || !itemObject->getString("type"_s, type)
            || type != "automation")
            continue;

        target.id = *targetId;
        target.name = name.utf8();
        targetList.append(target);
    }
    return targetList;
}

void SessionHost::receivedSetTargetList(const struct Event& event)
{
    ASSERT(isMainThread());

    if (!event.connectionID || !event.message)
        return;

    auto targetList = parseTargetList(event);
    if (targetList)
        setTargetList(*event.connectionID, WTFMove(*targetList));
}

void SessionHost::receivedSendMessageToFrontend(const struct Event& event)
{
    ASSERT(isMainThread());

    if (!event.connectionID || !event.targetID || !event.message)
        return;

    ASSERT(*event.connectionID == m_connectionID && *event.targetID == m_target.id);
    dispatchMessage(event.message.value());
}

void SessionHost::receivedStartAutomationSessionReturn(const struct Event&)
{
    ASSERT(isMainThread());

    m_capabilities.browserName = String::fromUTF8("TODO/browserName");
    m_capabilities.browserVersion = String::fromUTF8("TODO/browserVersion");
}

void SessionHost::startAutomationSession(Function<void (bool, std::optional<String>)>&& completionHandler)
{
    ASSERT(!m_startSessionCompletionHandler);
    m_startSessionCompletionHandler = WTFMove(completionHandler);
    m_sessionID = createCanonicalUUIDString();

    auto sendMessageEvent = JSON::Object::create();
    sendMessageEvent->setString("event"_s, "StartAutomationSession"_s);
    sendMessageEvent->setString("message"_s, m_sessionID);
    sendWebInspectorEvent(sendMessageEvent->toJSONString());
}

void SessionHost::setTargetList(uint64_t connectionID, Vector<Target>&& targetList)
{
    // The server notifies all its clients when connection is lost by sending an empty target list.
    // We only care about automation connection.
    if (m_connectionID && m_connectionID != connectionID)
        return;

    ASSERT(targetList.size() <= 1);
    if (targetList.isEmpty()) {
        // Disconnected from backend
        m_clientID = std::nullopt;
        inspectorDisconnected();
        return;
    }

    m_target = targetList[0];
    if (m_connectionID) {
        ASSERT(m_connectionID == connectionID);
        return;
    }

    if (!m_startSessionCompletionHandler) {
        // Session creation was already rejected.
        return;
    }

    m_connectionID = connectionID;

    auto sendEvent = JSON::Object::create();
    sendEvent->setString("event"_s, "Setup"_s);
    sendEvent->setInteger("connectionID"_s, m_connectionID);
    sendEvent->setInteger("targetID"_s, m_target.id);
    sendWebInspectorEvent(sendEvent->toJSONString());

    auto startSessionCompletionHandler = std::exchange(m_startSessionCompletionHandler, nullptr);
    startSessionCompletionHandler(true, std::nullopt);
}

void SessionHost::sendMessageToBackend(const String& message)
{
    auto sendEvent = JSON::Object::create();
    sendEvent->setString("event"_s, "SendMessageToBackend"_s);
    sendEvent->setInteger("connectionID"_s, m_connectionID);
    sendEvent->setInteger("targetID"_s, m_target.id);
    sendEvent->setString("message"_s, message);
    sendWebInspectorEvent(sendEvent->toJSONString());
}

} // namespace WebDriver
