#' @title Agregar Cuenta de Twitter
#' @description Agrega una cuenta de Twitter con cookies y la activa automaticamente. IMPORTANTE: Las cookies son obligatorias para activar la cuenta correctamente.
#' @param username Nombre de usuario
#' @param password Contrasena
#' @param email Email de la cuenta
#' @param email_password Contrasena del email
#' @param cookies Cookies de sesion (OBLIGATORIO - formato: "auth_token=...; ct0=...")
#' @param db_file Archivo de base de datos (default: "accounts.db")
#' @param verbose Si `TRUE`, emite mensajes informativos con `message()`/`warning()`; puede silenciarse con `suppressMessages()`/`suppressWarnings()`.
#' @return Invisibly returns `TRUE` if the account was added and is active; invisibly returns `FALSE` if it was not added, already existed, or could not be activated.
#' @export
#' @examples
#' \donttest{
#' if (check_setup() && interactive()) {
#'   # add_account(
#'   #   username = "your_username",
#'   #   password = "your_password",
#'   #   email = "you@example.com",
#'   #   email_password = "your_email_password",
#'   #   cookies = "auth_token=...; ct0=..."
#'   # )
#' }
#' }
add_account <- function(username, password, email, email_password, cookies, db_file = "accounts.db", verbose = TRUE) {
  if (missing(cookies) || length(cookies) != 1 || is.na(cookies) || !nzchar(cookies)) {
    stop("cookies is required. Use a string like 'auth_token=...; ct0=...'.", call. = FALSE)
  }

  ensure_configured()

  .account_message("Agregando Cuenta de Twitter", verbose = verbose)
  .account_message(sprintf("Usuario: @%s", username), verbose = verbose)

  cookies_str <- sprintf(", cookies=%s", .python_string_literal(cookies))

  result <- tryCatch({
    py_result <- reticulate::py_run_string(sprintf("
import asyncio
from twscrape import API
import sqlite3

async def add_account():
    db_path = %s
    conn = sqlite3.connect(db_path)
    conn.close()
    api = API(db_path)

    try:
        await api.pool.add_account(
            %s,
            %s,
            %s,
            %s%s
        )
        return {'success': True, 'message': 'Cuenta agregada'}
    except Exception as e:
        return {'success': False, 'message': str(e)}

_add_account_result = asyncio.run(add_account())
    ",
      .python_string_literal(db_file),
      .python_string_literal(username),
      .python_string_literal(password),
      .python_string_literal(email),
      .python_string_literal(email_password),
      cookies_str
    ))

    py_result$`_add_account_result`
  }, error = function(e) {
    list(success = FALSE, message = as.character(e))
  })

  if (result$success) {
    accounts_check <- tryCatch({
      py_check <- reticulate::py_run_string(sprintf("
import asyncio
from twscrape import API

async def check_account():
    api = API(%s)
    accounts = await api.pool.get_all()
    target = [acc for acc in accounts if acc.username == %s]
    if target:
        return {'active': target[0].active}
    return {'active': False}

_check_result = asyncio.run(check_account())
      ", .python_string_literal(db_file), .python_string_literal(username)))
      py_check$`_check_result`
    }, error = function(e) {
      list(active = FALSE)
    })

    if (accounts_check$active) {
      .account_message(sprintf("Cuenta @%s agregada y activada correctamente", username), verbose = verbose)
      .account_message("Listo. Ahora puedes usar search_tweets(), user_tweets() o search_hashtag().", verbose = verbose)
      return(invisible(TRUE))
    }

    .account_warning("Cuenta agregada pero no esta activa. Puede deberse a cookies invalidas o expiradas, credenciales incorrectas, o una cuenta suspendida/bloqueada.", verbose = verbose)
    .account_message("Solucion: verifica tus cookies en el navegador y vuelve a intentar.", verbose = verbose)
    return(invisible(FALSE))
  }

  if (grepl("already exists", result$message, ignore.case = TRUE)) {
    .account_warning(sprintf("La cuenta @%s ya existe. Usa list_accounts() para ver tus cuentas.", username), verbose = verbose)
  } else {
    .account_warning(sprintf("Error: %s", result$message), verbose = verbose)
  }

  return(invisible(FALSE))
}

#' @title Agregar Cuenta desde Variables de Entorno
#' @description Lee credenciales desde `.Renviron` o variables de entorno y agrega la cuenta sin exponer secretos en el codigo.
#' @param prefix Prefijo de las variables de entorno (default: "TWS_")
#' @param db_file Archivo de base de datos (default: "accounts.db")
#' @param verbose Si `TRUE`, emite mensajes informativos con `message()`/`warning()`; puede silenciarse con `suppressMessages()`/`suppressWarnings()`.
#' @return `TRUE` si la cuenta se agrego y activo; `FALSE` si se agrego pero no quedo activa o hubo error
#' @export
#' @examples
#' \donttest{
#' # En .Renviron:
#' # TWS_USERNAME='mi_usuario'
#' # TWS_PASSWORD='mi_password'
#' # TWS_EMAIL='mi@email.com'
#' # TWS_EMAIL_PASSWORD='email_pass'
#' # TWS_AUTH_TOKEN='auth_token_del_navegador'
#' # TWS_CT0='ct0_del_navegador'
#'
#' if (check_setup() && interactive()) {
#'   add_account_from_env()
#'
#'   # Para una segunda cuenta, usa otro prefijo:
#'   # TWS2_USERNAME='otra_cuenta'
#'   # TWS2_PASSWORD='otra_password'
#'   # ...
#'   add_account_from_env(prefix = "TWS2_")
#' }
#' }
add_account_from_env <- function(prefix = "TWS_", db_file = "accounts.db", verbose = TRUE) {
  account <- .account_env_values(prefix)

  .account_message(sprintf("Leyendo credenciales desde variables de entorno con prefijo %s", prefix), verbose = verbose)

  add_account(
    username = account$username,
    password = account$password,
    email = account$email,
    email_password = account$email_password,
    cookies = account$cookies,
    db_file = db_file,
    verbose = verbose
  )
}

.account_env_values <- function(prefix = "TWS_") {
  required_vars <- paste0(prefix, c("USERNAME", "PASSWORD", "EMAIL", "EMAIL_PASSWORD"))
  values <- .get_required_env(required_vars)

  list(
    username = values[[paste0(prefix, "USERNAME")]],
    password = values[[paste0(prefix, "PASSWORD")]],
    email = values[[paste0(prefix, "EMAIL")]],
    email_password = values[[paste0(prefix, "EMAIL_PASSWORD")]],
    cookies = .cookies_from_env(prefix)
  )
}

.cookies_from_env <- function(prefix = "TWS_") {
  cookies_var <- paste0(prefix, "COOKIES")
  cookies <- Sys.getenv(cookies_var, unset = NA_character_)
  has_cookies <- !is.na(cookies) && nzchar(cookies)

  if (has_cookies) {
    return(cookies)
  }

  auth_token_var <- paste0(prefix, "AUTH_TOKEN")
  ct0_var <- paste0(prefix, "CT0")
  token_values <- Sys.getenv(c(auth_token_var, ct0_var), unset = NA_character_)

  missing_cookie_vars <- names(token_values)[is.na(token_values) | !nzchar(token_values)]

  if (length(missing_cookie_vars) > 0) {
    stop(
      "Faltan cookies. Configura ", cookies_var,
      " o las variables: ", paste(c(auth_token_var, ct0_var), collapse = ", "),
      call. = FALSE
    )
  }

  paste0("auth_token=", token_values[[auth_token_var]], "; ct0=", token_values[[ct0_var]])
}

.get_required_env <- function(vars) {
  values <- Sys.getenv(vars, unset = NA_character_)
  missing_vars <- vars[is.na(values) | !nzchar(values)]

  if (length(missing_vars) > 0) {
    stop(
      "Faltan variables de entorno requeridas: ", paste(missing_vars, collapse = ", "),
      call. = FALSE
    )
  }

  as.list(stats::setNames(values, vars))
}

.python_string_literal <- function(x) {
  if (length(x) != 1 || is.na(x)) {
    stop("Se esperaba un string no vac\u00edo para construir el literal de Python.", call. = FALSE)
  }

  x <- as.character(x)
  x <- gsub("\\\\", "\\\\\\\\", x)
  x <- gsub("'", "\\\\'", x)
  x <- gsub("\n", "\\n", x, fixed = TRUE)
  x <- gsub("\r", "\\r", x, fixed = TRUE)
  paste0("'", x, "'")
}

#' @title Listar Cuentas
#' @description Lista todas las cuentas configuradas
#' @param db_file Archivo de base de datos (default: "accounts.db")
#' @param verbose Si `TRUE`, emite mensajes informativos con `message()`/`warning()`; puede silenciarse con `suppressMessages()`/`suppressWarnings()`.
#' @return Invisibly returns a list of configured accounts. Each account contains `username`, `email`, `active`, and `locks`; an empty list indicates no accounts or an error.
#' @export
#' @examples
#' \donttest{
#' if (check_setup()) {
#'   accounts <- list_accounts()
#'   print(accounts)
#' }
#' }
list_accounts <- function(db_file = "accounts.db", verbose = TRUE) {
  ensure_configured()

  result <- tryCatch({
    py_result <- reticulate::py_run_string(sprintf("
import asyncio
from twscrape import API

async def list_accounts():
    try:
        api = API(%s)
        accounts = await api.pool.get_all()
        return {
            'success': True,
            'accounts': [{
                'username': acc.username,
                'email': acc.email,
                'active': acc.active,
                'locks': acc.locks
            } for acc in accounts]
        }
    except Exception as e:
        return {'success': False, 'message': str(e), 'accounts': []}

_list_accounts_result = asyncio.run(list_accounts())
  ", .python_string_literal(db_file)))

    py_result$`_list_accounts_result`
  }, error = function(e) {
    error_msg <- as.character(e)
    list(success = FALSE, message = error_msg, accounts = list())
  })

  if (!result$success) {
    if (grepl("no such table", result$message, ignore.case = TRUE)) {
      .account_warning("No hay cuentas configuradas aun. Para comenzar, agrega tu primera cuenta con add_account(...).", verbose = verbose)
    } else {
      .account_warning(sprintf("Error al listar cuentas: %s", result$message), verbose = verbose)
    }
    return(invisible(list()))
  }

  accounts <- result$accounts

  if (length(accounts) == 0) {
    .account_warning("No hay cuentas configuradas. Agrega una cuenta con add_account(...).", verbose = verbose)
    return(invisible(list()))
  }

  .account_message(sprintf("Cuentas configuradas: %d", length(accounts)), verbose = verbose)

  df <- data.frame(
    username = sapply(accounts, function(x) x$username),
    email = sapply(accounts, function(x) x$email),
    active = sapply(accounts, function(x) x$active),
    stringsAsFactors = FALSE
  )

  if (isTRUE(verbose)) {
    message(paste(utils::capture.output(print(df)), collapse = "\n"))
  }

  return(invisible(accounts))
}

#' @title Eliminar Cuenta
#' @description Elimina una cuenta de la base de datos
#' @param username Nombre de usuario a eliminar
#' @param db_file Archivo de base de datos (default: "accounts.db")
#' @param verbose Si `TRUE`, emite mensajes informativos con `message()`/`warning()`; puede silenciarse con `suppressMessages()`/`suppressWarnings()`.
#' @return Invisibly returns `TRUE` if the account was deleted; invisibly returns `FALSE` otherwise.
#' @export
#' @examples
#' \donttest{
#' if (check_setup() && interactive()) {
#'   # delete_account("your_username")
#' }
#' }
delete_account <- function(username, db_file = "accounts.db", verbose = TRUE) {
  ensure_configured()

  .account_message(sprintf("Eliminando cuenta: @%s", username), verbose = verbose)

  result <- reticulate::py_run_string(sprintf("
import asyncio
from twscrape import API

async def delete_account():
    api = API(%s)
    try:
        await api.pool.delete_accounts(%s)
        return {'success': True}
    except Exception as e:
        return {'success': False, 'message': str(e)}

_delete_result = asyncio.run(delete_account())
  ", .python_string_literal(db_file), .python_string_literal(username)))

  res <- result$`_delete_result`

  if (res$success) {
    .account_message("Cuenta eliminada", verbose = verbose)
  } else {
    .account_warning(sprintf("Error: %s", res$message), verbose = verbose)
  }

  return(invisible(res$success))
}

.account_message <- function(text, verbose = TRUE) {
  if (isTRUE(verbose)) {
    message(text)
  }
}

.account_warning <- function(text, verbose = TRUE) {
  if (isTRUE(verbose)) {
    warning(text, call. = FALSE)
  }
}
