# skip tests on CRAN
skip_on_cran()
skip_if_not_installed("duckdb")
skip_if_not_installed("sf")

# Setup: connection and data
conn_test <- duckspatial::ddbs_create_conn()

# Write some data to test against
ddbs_write_table(conn_test, points_sf, "test_points_read", overwrite = TRUE)
ddbs_write_table(conn_test, countries_sf, "test_countries_read", overwrite = TRUE)
ddbs_register_table(conn_test, points_sf, "test_points_view_read", overwrite = TRUE)

# 1. Basic reading from tables and views ----
test_that("ddbs_read_table reads a table into an sf object", {
  # Read from a table created with ddbs_write_table
  result <- ddbs_read_table(conn_test, "test_points_read")

  expect_s3_class(result, "sf")
  expect_equal(nrow(result), nrow(points_sf))
  expect_equal(sf::st_crs(result), sf::st_crs(points_sf))
  expect_true(all(c("id", "geometry") %in% names(result)))
})

test_that("ddbs_read_table reads an Arrow view into an sf object", {
  # Read from a view created with ddbs_register_table
  result <- ddbs_read_table(conn_test, "test_points_view_read")

  expect_s3_class(result, "sf")
  expect_equal(nrow(result), nrow(points_sf))
  expect_equal(sf::st_crs(result), sf::st_crs(points_sf))
})

test_that("ddbs_read_table reads a standard SQL view into an sf object", {
  # Create a standard SQL view from an existing table
  # First ensure the base table exists
  ddbs_write_table(conn_test, points_sf, "base_table_for_view", overwrite = TRUE)
  
  # Create SQL view
  DBI::dbExecute(conn_test, "CREATE OR REPLACE VIEW test_sql_view AS SELECT * FROM base_table_for_view")
  
  # Read from the SQL view
  result <- ddbs_read_table(conn_test, "test_sql_view")
  
  expect_s3_class(result, "sf")
  expect_equal(nrow(result), nrow(points_sf))
  expect_equal(sf::st_crs(result), sf::st_crs(points_sf))
  
  # Cleanup
  DBI::dbExecute(conn_test, "DROP VIEW IF EXISTS test_sql_view")
})

# 2. Parameters and clauses ----
test_that("ddbs_read_table's 'clauses' argument works", {
  # Use a WHERE clause to filter the data
  result <- ddbs_read_table(conn_test, "test_points_read", clauses = "WHERE id <= 3")

  expect_equal(nrow(result), 3)
  expect_true(all(result$id <= 3))
})

test_that("ddbs_read_table works with different geometry types", {
  # Test with polygons
  result <- ddbs_read_table(conn_test, "test_countries_read")
  expect_s3_class(result, "sf")
  expect_true(any(grepl("POLYGON", sf::st_geometry_type(result))))
})

# 3. CRS handling ----
test_that("ddbs_read_table infers CRS from crs_duckspatial column", {
  # The 'test_points_read' table has crs_duckspatial = '4326'
  result <- ddbs_read_table(conn_test, "test_points_read")
  expect_equal(sf::st_crs(result), sf::st_crs(4326))
})

test_that("ddbs_read_table handles tables with no CRS info", {
  # Create a table with no CRS
  points_no_crs <- points_sf
  sf::st_crs(points_no_crs) <- NA
  ddbs_write_table(conn = conn_test, data = points_no_crs, name = "test_no_crs_read", overwrite = TRUE)

  # Read without specifying CRS (should result in NA CRS)
  result <- ddbs_read_table(conn_test, "test_no_crs_read")
  expect_true(is.na(sf::st_crs(result)))
})

# 4. Errors ----
test_that("ddbs_read_table throws an error for non-existent tables/views", {
  expect_error(
    ddbs_read_table(conn_test, "this_table_does_not_exist"),
    "not present in the database"
  )
})

# Disconnect
duckdb::dbDisconnect(conn_test, shutdown = TRUE)
