# google_sheets.R

#' Export a survey instrument to Google Sheets collection format
#'
#' Generates a Google Apps Script file that, when run in a Google Sheet,
#' creates a response collection endpoint for a survey instrument. The builder
#' can store the deployed Apps Script URL in survey metadata, and the same
#' sheet can be read back with [read_sheet_responses()].
#'
#' @param instrument An `sframe` object.
#' @param sheet_url Character. The URL of an existing Google Sheet. The sheet
#'   must be shared so that anyone with the link can edit, or use service
#'   account credentials via `googlesheets4`.
#' @param output_dir Character. Directory to write the Apps Script file.
#'   Defaults to the current working directory.
#'
#' @return The path to the generated `.gs` Apps Script file, invisibly.
#' @export
#' @seealso [read_sheet_responses()], [read_responses()], [write_sframe()]
#'
#' @examples
#' instr <- read_sframe(
#'   system.file("extdata", "tourism_services_demo.sframe",
#'               package = "surveyframe")
#' )
#' script <- export_google_sheet(
#'   instr,
#'   sheet_url = "https://docs.google.com/spreadsheets/d/demo",
#'   output_dir = tempdir()
#' )
#' file.exists(script)
export_google_sheet <- function(instrument, sheet_url, output_dir = ".") {
  stopifnot(inherits(instrument, "sframe"))
  if (!dir.exists(output_dir)) {
    rlang::abort(
      paste0("Output directory does not exist: '", output_dir, "'."),
      class = "sframe_error"
    )
  }

  item_ids <- vapply(instrument$items, function(i) i$id, character(1))
  col_headers <- c("respondent_id", "started_at", "submitted_at", item_ids)
  headers_js <- jsonlite::toJSON(col_headers, auto_unbox = TRUE)
  sheet_url_js <- jsonlite::toJSON(sheet_url %||% "", auto_unbox = TRUE)
  sheet_url_comment <- gsub("[\r\n]+", " ", sheet_url %||% "", perl = TRUE)

  script <- sprintf(
'// Google Apps Script for surveyframe response collection
// Generated by surveyframe::export_google_sheet()
// Target Google Sheet: %s
//
// Setup:
// 1. Open the target Google Sheet
// 2. Go to Extensions > Apps Script
// 3. Paste this entire file, replacing any existing code
// 4. Click Deploy > New deployment > Web app
// 5. Set "Who has access" to "Anyone"
// 6. Copy the Web App URL and paste it into the SurveyBuilder
//    under Survey > Google Sheets Setup

const SHEET_NAME = "Responses";
const TARGET_SHEET_URL = %s;
const EXPECTED_COLUMNS = %s;
const MAX_BODY_CHARS = 200000;

function doPost(e) {
  try {
    if (!e || !e.postData || !e.postData.contents) {
      throw new Error("Missing POST body.");
    }
    if (e.postData.contents.length > MAX_BODY_CHARS) {
      throw new Error("POST body too large.");
    }
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    let sheet = ss.getSheetByName(SHEET_NAME);

    if (!sheet) {
      sheet = ss.insertSheet(SHEET_NAME);
      sheet.appendRow(EXPECTED_COLUMNS);
      sheet.getRange(1, 1, 1, EXPECTED_COLUMNS.length)
           .setFontWeight("bold")
           .setBackground("#1a1a2e")
           .setFontColor("#ffffff");
    }

    const data = JSON.parse(e.postData.contents);
    if (!data || Array.isArray(data) || typeof data !== "object") {
      throw new Error("POST body must be a JSON object.");
    }
    const row = EXPECTED_COLUMNS.map(col => data[col] !== undefined ? data[col] : "");
    sheet.appendRow(row);

    return ContentService
      .createTextOutput(JSON.stringify({ status: "ok", rows: sheet.getLastRow() - 1 }))
      .setMimeType(ContentService.MimeType.JSON);

  } catch (err) {
    return ContentService
      .createTextOutput(JSON.stringify({ status: "error", message: err.toString() }))
      .setMimeType(ContentService.MimeType.JSON);
  }
}

function doGet(e) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(SHEET_NAME);
  if (!sheet) {
    return ContentService
      .createTextOutput(JSON.stringify({ status: "ok", rows: 0 }))
      .setMimeType(ContentService.MimeType.JSON);
  }
  const lastRow = sheet.getLastRow();
  return ContentService
    .createTextOutput(JSON.stringify({ status: "ok", rows: Math.max(0, lastRow - 1) }))
    .setMimeType(ContentService.MimeType.JSON);
}
',
    sheet_url_comment,
    sheet_url_js,
    headers_js
  )

  out_path <- file.path(output_dir, "surveyframe_collector.gs")
  writeLines(script, out_path)

  message(
    "Apps Script written to: ", out_path, "\n",
    "Follow the setup instructions inside the file to deploy it."
  )
  invisible(out_path)
}

#' Read survey responses from a Google Sheet
#'
#' Reads response data collected by the surveyframe Google Apps Script
#' endpoint and returns a validated data frame ready for the surveyframe
#' analysis pipeline.
#'
#' @param sheet_id Character. The Google Sheet ID or full URL.
#' @param instrument An `sframe` object.
#' @param sheet_name Character. The name of the sheet tab holding responses.
#'   Defaults to `"Responses"`.
#' @param respondent_id Character or NULL. Column holding respondent IDs.
#'   Defaults to `"respondent_id"`.
#' @param submitted_at Character or NULL. Column holding submission
#'   timestamps. Defaults to `"submitted_at"`.
#'
#' @return A `data.frame` validated against the instrument, ready for
#'   [quality_report()], [score_scales()], and [reliability_report()].
#' @export
#' @seealso [export_google_sheet()], [read_responses()], [quality_report()]
#'
#' @examples
#' \dontrun{
#' responses <- read_sheet_responses(
#'   sheet_id   = "your-sheet-id",
#'   instrument = instr
#' )
#' qr <- quality_report(responses, instr, respondent_id = "respondent_id")
#' }
read_sheet_responses <- function(
    sheet_id,
    instrument,
    sheet_name    = "Responses",
    respondent_id = "respondent_id",
    submitted_at  = "submitted_at"
) {
  rlang::check_installed("googlesheets4",
    reason = "to read responses from Google Sheets")
  stopifnot(inherits(instrument, "sframe"))

  raw <- googlesheets4::read_sheet(sheet_id, sheet = sheet_name,
                                    col_types = "c")

  read_responses(
    x             = raw,
    instrument    = instrument,
    respondent_id = respondent_id,
    submitted_at  = submitted_at,
    strict        = FALSE
  )
}
