#include <js/workers/fetch_rows_worker.h>

#include <utils/Logger.h>
#include <common/odbc_common.h>
#include <js/js_object_mapper.h>
#include <odbc/odbc_row.h>
#include <platform.h>

namespace mssql {

FetchRowsWorker::FetchRowsWorker(Napi::Function& callback,
                                 IOdbcConnection* connection,
                                 const StatementHandle& statementHandle,
                                 const QueryOptions& options)
    : OdbcAsyncWorker(callback, connection), statementHandle_(statementHandle), options_(options) {
  SQL_LOG_DEBUG_STREAM(
      "FetchRowsWorker constructor for statement: " << statementHandle_.toString());
  result_ = std::make_shared<QueryResult>(statementHandle_);
}

void FetchRowsWorker::Execute() {
  try {
    SQL_LOG_DEBUG_STREAM(
        "Executing FetchRowsWorker for statement: " << statementHandle_.toString());

    if (!statementHandle_.isValid()) {
      SetError("Invalid statement handle");
      return;
    }

    const auto statement = GetStatement();
    if (!statement) {
      SetError("Statement not found");
      return;
    }

    if (!statement->TryReadRows(result_, options_.batch_size)) {
      const auto& errors = connection_->GetErrors();
      if (!errors.empty()) {
        // Populate errorDetails_ with all ODBC errors
        errorDetails_ = errors;
        const std::string errorMessage = errors[0]->message;
        SetError(errorMessage);
        has_error_ = true;
      }
    }
  } catch (const std::exception& e) {
    SQL_LOG_ERROR("Exception in FetchRowsWorker::Execute: " + std::string(e.what()));
    SetError("Exception occurred: " + std::string(e.what()));
  } catch (...) {
    SQL_LOG_ERROR("Unknown exception in FetchRowsWorker::Execute");
    SetError("Unknown exception occurred");
  }
}

void FetchRowsWorker::OnOK() {
  if (has_error_) {
    SQL_LOG_ERROR_STREAM("Error in FetchRowsWorker::OnOK: dispatching error via OnError path");
    const Napi::Env env = Env();
    Napi::HandleScope scope(env);
    const auto errorArg = GetErrors(env);
    const auto meta = GetMetadata();
    Callback().Call({errorArg, meta, Napi::Boolean::New(env, !result_->is_end_of_results())});
    return;
  }

  const Napi::Env env = Env();
  Napi::HandleScope scope(env);
  SQL_LOG_DEBUG("FetchRowsWorker::OnOK");

  try {
    const auto statement = GetStatement();
    if (!statement) {
      SQL_LOG_ERROR("FetchRowsWorker::OnOK - statement no longer available (freed during async gap)");
      Callback().Call({Napi::Error::New(env, "Statement handle was freed before results could be returned").Value(), env.Null()});
      return;
    }
    const auto resultset = statement->GetResultSet();
    if (!resultset) {
      SQL_LOG_ERROR("FetchRowsWorker::OnOK - result set is null");
      Callback().Call({Napi::Error::New(env, "Result set is null").Value(), env.Null()});
      return;
    }
    const auto result = JsObjectMapper::fromQueryResult(env, resultset);
    // Call the callback with the result
    Callback().Call({env.Null(), result});
  } catch (const std::exception& e) {
    // Call the callback with an error
    Callback().Call({Napi::Error::New(env, e.what()).Value(), env.Null()});
  }
}
}  // namespace mssql