// Phase 0 toolchain proof: open an lt::session, add a well-known public-domain
// magnet (Sintel, the Blender Foundation's CC-licensed short film, commonly
// used as a test torrent), poll alerts for progress, and shut down cleanly.

#include <libtorrent/alert_types.hpp>
#include <libtorrent/add_torrent_params.hpp>
#include <libtorrent/magnet_uri.hpp>
#include <libtorrent/session.hpp>
#include <libtorrent/settings_pack.hpp>
#include <libtorrent/torrent_status.hpp>

#include <chrono>
#include <cstdlib>
#include <filesystem>
#include <iostream>
#include <thread>

namespace lt = libtorrent;

namespace {
constexpr auto kMagnet =
    "magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10"
    "&dn=Sintel"
    "&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce"
    "&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A6969%2Fannounce";
}

int main() {
  const auto save_path = std::filesystem::temp_directory_path() / "torlink-cpp-phase0";
  std::filesystem::create_directories(save_path);

  lt::settings_pack pack;
  pack.set_int(lt::settings_pack::alert_mask,
               lt::alert_category::status | lt::alert_category::error);

  lt::session ses(pack);

  lt::error_code ec;
  lt::add_torrent_params params = lt::parse_magnet_uri(kMagnet, ec);
  if (ec) {
    std::cerr << "failed to parse magnet: " << ec.message() << "\n";
    return 1;
  }
  params.save_path = save_path.string();

  ses.async_add_torrent(std::move(params));

  std::cout << "session started, listening on port "
            << ses.listen_port() << "\n";
  std::cout << "watching '" << kMagnet << "' for 10s (save path: "
            << save_path << ")\n";

  lt::torrent_handle handle;

  for (int tick = 0; tick < 20; ++tick) {
    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    std::vector<lt::alert*> alerts;
    ses.pop_alerts(&alerts);
    for (lt::alert* a : alerts) {
      if (auto* at = lt::alert_cast<lt::add_torrent_alert>(a)) {
        handle = at->handle;
        std::cout << "[alert] torrent added: " << at->handle.status().name
                  << "\n";
      } else if (auto* mt = lt::alert_cast<lt::metadata_received_alert>(a)) {
        std::cout << "[alert] metadata received: "
                  << mt->handle.status().name << "\n";
      } else if (auto* st = lt::alert_cast<lt::state_update_alert>(a)) {
        for (const lt::torrent_status& s : st->status) {
          std::cout << "[status] progress=" << (s.progress * 100.0) << "% "
                    << "peers=" << s.num_peers << " "
                    << "down=" << s.download_rate << "B/s"
                    << "\n";
        }
      } else if (auto* et = lt::alert_cast<lt::torrent_error_alert>(a)) {
        std::cout << "[alert] torrent error: " << et->message() << "\n";
      } else if (auto* lf = lt::alert_cast<lt::listen_failed_alert>(a)) {
        std::cout << "[alert] listen failed: " << lf->message() << "\n";
      }
    }

    ses.post_torrent_updates();
  }

  if (handle.is_valid()) {
    ses.remove_torrent(handle);
  }

  std::cout << "shutting down cleanly\n";
  return 0;
}
