#include "config.h"

#include "thread_session.h"

#include <torrent/exceptions.h>

#include "globals.h"
#include "session/session_manager.h"

namespace session {

ThreadSession* ThreadSession::m_thread_session{nullptr};

void
ThreadSession::create_thread() {
  auto thread = new ThreadSession;

  thread->m_manager = std::make_unique<SessionManager>(thread);

  m_thread_session          = thread;
  m_thread_session->m_state = STATE_INITIALIZED;
}

void
ThreadSession::destroy_thread() {
  delete m_thread_session;
  m_thread_session = nullptr;
}

ThreadSession*
ThreadSession::thread_session() {
  return m_thread_session;
}

void
ThreadSession::init_thread_pre_start() {
  m_manager->start();
}

// TODO: Make sure we trigger session save before main thread exits, that it adds all required
// downloads to the queue.
void
ThreadSession::cleanup_thread() {
  m_manager->cleanup();
}

void
ThreadSession::call_events() {
  // lt_log_print_locked(torrent::LOG_THREAD_NOTICE, "Got thread_disk tick.");

  process_callbacks();

  if ((m_flags & flag_do_shutdown)) {
    if ((m_flags & flag_did_shutdown))
      throw torrent::internal_error("Already trigged shutdown.");

    m_flags |= flag_did_shutdown;
    throw torrent::shutdown_exception();
  }
}

std::chrono::microseconds
ThreadSession::next_timeout() {
  // TODO: This leads to kqueue crash?
  // return std::chrono::microseconds(1h);
  return std::chrono::microseconds(10min);
}

} // namespace session

namespace session_thread {

torrent::system::Thread* thread()                                           { return session::ThreadSession::thread_session(); }
std::thread::id          thread_id()                                        { return thread()->thread_id(); }

void callback(std::function<void()>&& fn)                                   { thread()->callback(std::move(fn)); }
void callback(torrent::system::callback_id& id, std::function<void()>&& fn) { thread()->callback(id, std::move(fn)); }
void cancel_callback(torrent::system::callback_id& id)                      { thread()->cancel_callback(id); }

session::SessionManager* manager()                                          { return session::ThreadSession::thread_session()->manager(); }
std::string              session_path()                                     { return manager()->path(); }

} // namespace session_thread
