// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cast/receiver/application_agent.h"

#include <utility>

#include "cast/common/channel/message_util.h"
#include "cast/common/channel/virtual_connection.h"
#include "cast/common/public/cast_socket.h"
#include "platform/base/tls_credentials.h"
#include "platform/base/tls_listen_options.h"
#include "util/json/json_serialization.h"
#include "util/osp_logging.h"

namespace openscreen {
namespace cast {
namespace {

// Parses the given string as a JSON object. If the parse fails, an empty object
// is returned.
Json::Value ParseAsObject(absl::string_view value) {
  ErrorOr<Json::Value> parsed = json::Parse(value);
  if (parsed.is_value() && parsed.value().isObject()) {
    return std::move(parsed.value());
  }
  return Json::Value(Json::objectValue);
}

// Returns true if the type field in |object| is set to the given |type|.
bool HasType(const Json::Value& object, CastMessageType type) {
  OSP_DCHECK(object.isObject());
  const Json::Value& value =
      object.get(kMessageKeyType, Json::Value::nullSingleton());
  return value.isString() && value.asString() == CastMessageTypeToString(type);
}

// Returns the first app ID for the given |app|, or the empty string if there is
// none.
std::string GetFirstAppId(ApplicationAgent::Application* app) {
  const auto& app_ids = app->GetAppIds();
  return app_ids.empty() ? std::string() : app_ids.front();
}

}  // namespace

ApplicationAgent::ApplicationAgent(
    TaskRunner* task_runner,
    DeviceAuthNamespaceHandler::CredentialsProvider* credentials_provider)
    : task_runner_(task_runner),
      auth_handler_(credentials_provider),
      connection_handler_(&router_, this),
      message_port_(&router_) {
  router_.AddHandlerForLocalId(kPlatformReceiverId, this);
}

ApplicationAgent::~ApplicationAgent() {
  OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());

  idle_screen_app_ = nullptr;  // Prevent re-launching the idle screen app.
  SwitchToApplication({}, {}, nullptr);

  router_.RemoveHandlerForLocalId(kPlatformReceiverId);
}

void ApplicationAgent::RegisterApplication(Application* app,
                                           bool auto_launch_for_idle_screen) {
  OSP_DCHECK(app);

  for (const std::string& app_id : app->GetAppIds()) {
    OSP_DCHECK(!app_id.empty());
    const auto insert_result = registered_applications_.insert({app_id, app});
    // The insert must not fail (prior entry for same key).
    OSP_DCHECK(insert_result.second);
  }

  if (auto_launch_for_idle_screen) {
    OSP_DCHECK(!idle_screen_app_);
    idle_screen_app_ = app;
    // Launch the idle screen app, if no app was running.
    if (!launched_app_) {
      GoIdle();
    }
  }
}

void ApplicationAgent::UnregisterApplication(Application* app) {
  for (auto it = registered_applications_.begin();
       it != registered_applications_.end();) {
    if (it->second == app) {
      it = registered_applications_.erase(it);
    } else {
      ++it;
    }
  }

  if (idle_screen_app_ == app) {
    idle_screen_app_ = nullptr;
  }

  if (launched_app_ == app) {
    GoIdle();
  }
}

void ApplicationAgent::StopApplicationIfRunning(Application* app) {
  if (launched_app_ == app) {
    GoIdle();
  }
}

void ApplicationAgent::OnConnected(ReceiverSocketFactory* factory,
                                   const IPEndpoint& endpoint,
                                   std::unique_ptr<CastSocket> socket) {
  router_.TakeSocket(this, std::move(socket));
}

void ApplicationAgent::OnError(ReceiverSocketFactory* factory, Error error) {
  OSP_LOG_ERROR << "Cast agent received socket factory error: " << error;
}

void ApplicationAgent::OnMessage(VirtualConnectionRouter* router,
                                 CastSocket* socket,
                                 ::cast::channel::CastMessage message) {
  if (message_port_.GetSocketId() == ToCastSocketId(socket) &&
      !message_port_.client_sender_id().empty() &&
      message_port_.client_sender_id() == message.destination_id()) {
    OSP_DCHECK(message_port_.client_sender_id() != kPlatformReceiverId);
    message_port_.OnMessage(router, socket, std::move(message));
    return;
  }

  if (message.destination_id() != kPlatformReceiverId &&
      message.destination_id() != kBroadcastId) {
    return;  // Message not for us.
  }

  const std::string& ns = message.namespace_();
  if (ns == kAuthNamespace) {
    auth_handler_.OnMessage(router, socket, std::move(message));
    return;
  }

  const Json::Value request = ParseAsObject(message.payload_utf8());
  Json::Value response;
  if (ns == kHeartbeatNamespace) {
    if (HasType(request, CastMessageType::kPing)) {
      response = HandlePing();
    }
  } else if (ns == kReceiverNamespace) {
    if (request[kMessageKeyRequestId].isNull()) {
      response = HandleInvalidCommand(request);
    } else if (HasType(request, CastMessageType::kGetAppAvailability)) {
      response = HandleGetAppAvailability(request);
    } else if (HasType(request, CastMessageType::kGetStatus)) {
      response = HandleGetStatus(request);
    } else if (HasType(request, CastMessageType::kLaunch)) {
      response = HandleLaunch(request, socket);
    } else if (HasType(request, CastMessageType::kStop)) {
      response = HandleStop(request);
    } else {
      response = HandleInvalidCommand(request);
    }
  } else {
    // Ignore messages for all other namespaces.
  }

  if (!response.empty()) {
    router_.Send(VirtualConnection{message.destination_id(),
                                   message.source_id(), ToCastSocketId(socket)},
                 MakeSimpleUTF8Message(ns, json::Stringify(response).value()));
  }
}

bool ApplicationAgent::IsConnectionAllowed(
    const VirtualConnection& virtual_conn) const {
  if (virtual_conn.local_id == kPlatformReceiverId) {
    return true;
  }
  if (!launched_app_ || message_port_.client_sender_id().empty()) {
    // No app currently launched. Or, there is a launched app, but it did not
    // call MessagePort::SetClient() to indicate it wants messages routed to it.
    return false;
  }
  return virtual_conn.local_id == message_port_.client_sender_id();
}

void ApplicationAgent::OnClose(CastSocket* socket) {
  if (message_port_.GetSocketId() == ToCastSocketId(socket)) {
    OSP_VLOG << "Cast agent socket closed.";
    GoIdle();
  }
}

void ApplicationAgent::OnError(CastSocket* socket, Error error) {
  if (message_port_.GetSocketId() == ToCastSocketId(socket)) {
    OSP_LOG_ERROR << "Cast agent received socket error: " << error;
    GoIdle();
  }
}

Json::Value ApplicationAgent::HandlePing() {
  Json::Value response;
  response[kMessageKeyType] = CastMessageTypeToString(CastMessageType::kPong);
  return response;
}

Json::Value ApplicationAgent::HandleGetAppAvailability(
    const Json::Value& request) {
  Json::Value response;
  const Json::Value& app_ids = request[kMessageKeyAppId];
  if (app_ids.isArray()) {
    response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
    response[kMessageKeyResponseType] = request[kMessageKeyType];
    Json::Value& availability = response[kMessageKeyAvailability];
    for (const Json::Value& app_id : app_ids) {
      if (app_id.isString()) {
        const auto app_id_str = app_id.asString();
        availability[app_id_str] = registered_applications_.count(app_id_str)
                                       ? kMessageValueAppAvailable
                                       : kMessageValueAppUnavailable;
      }
    }
  }
  return response;
}

Json::Value ApplicationAgent::HandleGetStatus(const Json::Value& request) {
  Json::Value response;
  PopulateReceiverStatus(&response);
  response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
  return response;
}

Json::Value ApplicationAgent::HandleLaunch(const Json::Value& request,
                                           CastSocket* socket) {
  const Json::Value& app_id = request[kMessageKeyAppId];
  Error error;
  if (app_id.isString() && !app_id.asString().empty()) {
    error = SwitchToApplication(app_id.asString(),
                                request[kMessageKeyAppParams], socket);
  } else {
    error = Error(Error::Code::kParameterInvalid, kMessageValueBadParameter);
  }
  if (!error.ok()) {
    Json::Value response;
    response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
    response[kMessageKeyType] =
        CastMessageTypeToString(CastMessageType::kLaunchError);
    response[kMessageKeyReason] = error.message();
    return response;
  }

  // Note: No reply is sent. Instead, the requestor will get a RECEIVER_STATUS
  // broadcast message from SwitchToApplication(), which is how it will see that
  // the launch succeeded.
  return {};
}

Json::Value ApplicationAgent::HandleStop(const Json::Value& request) {
  const Json::Value& session_id = request[kMessageKeySessionId];
  if (session_id.isNull()) {
    GoIdle();
    return {};
  }

  if (session_id.isString() && launched_app_ &&
      session_id.asString() == launched_app_->GetSessionId()) {
    GoIdle();
    return {};
  }

  Json::Value response;
  response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
  response[kMessageKeyType] =
      CastMessageTypeToString(CastMessageType::kInvalidRequest);
  response[kMessageKeyReason] = kMessageValueInvalidSessionId;
  return response;
}

Json::Value ApplicationAgent::HandleInvalidCommand(const Json::Value& request) {
  Json::Value response;
  if (request[kMessageKeyRequestId].isNull()) {
    return response;
  }
  response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
  response[kMessageKeyType] =
      CastMessageTypeToString(CastMessageType::kInvalidRequest);
  response[kMessageKeyReason] = kMessageValueInvalidCommand;
  return response;
}

Error ApplicationAgent::SwitchToApplication(std::string app_id,
                                            const Json::Value& app_params,
                                            CastSocket* socket) {
  Error error = Error::Code::kNone;
  Application* desired_app = nullptr;
  Application* fallback_app = nullptr;
  if (!app_id.empty()) {
    const auto it = registered_applications_.find(app_id);
    if (it != registered_applications_.end()) {
      desired_app = it->second;
      if (desired_app != idle_screen_app_) {
        fallback_app = idle_screen_app_;
      }
    } else {
      return Error(Error::Code::kItemNotFound, kMessageValueNotFound);
    }
  }

  if (launched_app_ == desired_app) {
    return error;
  }

  if (launched_app_) {
    launched_app_->Stop();
    message_port_.SetSocket({});
    launched_app_ = nullptr;
    launched_via_app_id_ = {};
  }

  if (desired_app) {
    if (socket) {
      message_port_.SetSocket(socket->GetWeakPtr());
    }
    if (desired_app->Launch(app_id, app_params, &message_port_)) {
      launched_app_ = desired_app;
      launched_via_app_id_ = std::move(app_id);
    } else {
      error = Error(Error::Code::kUnknownError, kMessageValueSystemError);
      message_port_.SetSocket({});
    }
  }

  if (!launched_app_ && fallback_app) {
    app_id = GetFirstAppId(fallback_app);
    if (fallback_app->Launch(app_id, {}, &message_port_)) {
      launched_app_ = fallback_app;
      launched_via_app_id_ = std::move(app_id);
    }
  }

  BroadcastReceiverStatus();

  return error;
}

void ApplicationAgent::GoIdle() {
  std::string app_id;
  if (idle_screen_app_) {
    app_id = GetFirstAppId(idle_screen_app_);
  }
  SwitchToApplication(app_id, {}, nullptr);
}

void ApplicationAgent::PopulateReceiverStatus(Json::Value* out) {
  Json::Value& message = *out;
  message[kMessageKeyType] =
      CastMessageTypeToString(CastMessageType::kReceiverStatus);
  Json::Value& status = message[kMessageKeyStatus];

  if (launched_app_) {
    Json::Value& details = status[kMessageKeyApplications][0];
    // If the Application can send/receive messages, the destination for such
    // messages is provided here, in |transportId|. However, the other end must
    // first set up the virtual connection by issuing a CONNECT request.
    // Otherwise, messages will not get routed to the Application by the
    // VirtualConnectionRouter.
    if (!message_port_.client_sender_id().empty()) {
      details[kMessageKeyTransportId] = message_port_.client_sender_id();
    }
    details[kMessageKeySessionId] = launched_app_->GetSessionId();
    details[kMessageKeyAppId] = launched_via_app_id_;
    details[kMessageKeyUniversalAppId] = launched_via_app_id_;
    details[kMessageKeyDisplayName] = launched_app_->GetDisplayName();
    details[kMessageKeyIsIdleScreen] = (launched_app_ == idle_screen_app_);
    details[kMessageKeyLaunchedFromCloud] = false;
    std::vector<std::string> app_namespaces =
        launched_app_->GetSupportedNamespaces();
    Json::Value& namespaces =
        (details[kMessageKeyNamespaces] = Json::Value(Json::arrayValue));
    for (int i = 0, count = app_namespaces.size(); i < count; ++i) {
      namespaces[i][kMessageKeyName] = std::move(app_namespaces[i]);
    }
  }

  status[kMessageKeyUserEq] = Json::Value(Json::objectValue);

  // Indicate a fixed 100% volume level.
  Json::Value& volume = status[kMessageKeyVolume];
  volume[kMessageKeyControlType] = kMessageValueAttenuation;
  volume[kMessageKeyLevel] = 1.0;
  volume[kMessageKeyMuted] = false;
  volume[kMessageKeyStepInterval] = 0.05;
}

void ApplicationAgent::BroadcastReceiverStatus() {
  Json::Value message;
  PopulateReceiverStatus(&message);
  message[kMessageKeyRequestId] = Json::Value(0);  // Indicates no requestor.
  router_.BroadcastFromLocalPeer(
      kPlatformReceiverId,
      MakeSimpleUTF8Message(kReceiverNamespace,
                            json::Stringify(message).value()));
}

ApplicationAgent::Application::~Application() = default;

}  // namespace cast
}  // namespace openscreen
