// Copyright 2022 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#pragma once

#include <cstddef>
#include <cstdint>
#include <limits>

#include "pw_bytes/span.h"
#include "pw_transfer/handler.h"
#include "pw_transfer/internal/config.h"
#include "pw_transfer/internal/server_context.h"
#include "pw_transfer/transfer.raw_rpc.pb.h"
#include "pw_transfer/transfer_thread.h"

namespace pw::transfer {
namespace internal {

class Chunk;

}  // namespace internal

class TransferService : public pw_rpc::raw::Transfer::Service<TransferService> {
 public:
  // Initializes a TransferService that can be registered with an RPC server.
  //
  // The transfer service requires a work queue to perform deferred tasks, such
  // as handling transfer timeouts and retries. This work queue does not need to
  // be unique to the transfer service; it may be shared with other parts of the
  // system.
  //
  // The provided buffer is used to stage data from transfer chunks before it is
  // written out to the writer. The size of this buffer is the largest amount of
  // data that can be sent in a single transfer chunk, excluding any transport
  // layer overhead.
  //
  // max_pending_bytes is the maximum amount of data to ask for at a
  // time during a write transfer, unless told a more restrictive amount by a
  // transfer handler. This size can span multiple chunks. A larger value
  // generally increases the efficiency of write transfers when sent over a
  // reliable transport. However, if the underlying transport is unreliable,
  // larger values could slow down a transfer in the event of repeated packet
  // loss.
  TransferService(
      TransferThread& transfer_thread,
      uint32_t max_pending_bytes,
      chrono::SystemClock::duration chunk_timeout = cfg::kDefaultChunkTimeout,
      uint8_t max_retries = cfg::kDefaultMaxRetries,
      uint32_t extend_window_divisor = cfg::kDefaultExtendWindowDivisor)
      : max_parameters_(max_pending_bytes,
                        transfer_thread.max_chunk_size(),
                        extend_window_divisor),
        thread_(transfer_thread),
        chunk_timeout_(chunk_timeout),
        max_retries_(max_retries) {}

  TransferService(const TransferService&) = delete;
  TransferService(TransferService&&) = delete;

  TransferService& operator=(const TransferService&) = delete;
  TransferService& operator=(TransferService&&) = delete;

  void Read(RawServerReaderWriter& reader_writer) {
    reader_writer.set_on_next([this](ConstByteSpan message) {
      HandleChunk(message, internal::TransferType::kTransmit);
    });
    thread_.SetServerReadStream(reader_writer);
  }

  void Write(RawServerReaderWriter& reader_writer) {
    reader_writer.set_on_next([this](ConstByteSpan message) {
      HandleChunk(message, internal::TransferType::kReceive);
    });
    thread_.SetServerWriteStream(reader_writer);
  }

  void RegisterHandler(internal::Handler& handler) {
    thread_.AddTransferHandler(handler);
  }

  void set_max_pending_bytes(uint32_t max_pending_bytes) {
    max_parameters_.set_pending_bytes(max_pending_bytes);
  }

  // Sets the maximum size for the data in a pw_transfer chunk. Note that the
  // max chunk size must always fit within the transfer thread's chunk buffer.
  void set_max_chunk_size_bytes(uint32_t max_chunk_size_bytes) {
    max_parameters_.set_max_chunk_size_bytes(max_chunk_size_bytes);
  }

  void UnregisterHandler(internal::Handler& handler) {
    thread_.RemoveTransferHandler(handler);
  }

  void set_chunk_timeout(chrono::SystemClock::duration chunk_timeout) {
    chunk_timeout_ = chunk_timeout;
  }

  void set_max_retries(uint8_t max_retries) { max_retries_ = max_retries; }

  Status set_extend_window_divisor(uint32_t extend_window_divisor) {
    if (extend_window_divisor <= 1) {
      return Status::InvalidArgument();
    }

    max_parameters_.set_extend_window_divisor(extend_window_divisor);
    return OkStatus();
  }

 private:
  void HandleChunk(ConstByteSpan message, internal::TransferType type);

  internal::TransferParameters max_parameters_;
  TransferThread& thread_;

  chrono::SystemClock::duration chunk_timeout_;
  uint8_t max_retries_;
};

}  // namespace pw::transfer
