# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

# Test timestamp predicate pushdown behavior
#
# When you CREATE TABLE with TIMESTAMP in DataFusion, it creates a TimestampNs column
# (nanosecond precision) in Iceberg, since DataFusion's default TIMESTAMP type is nanoseconds.
#
# We use Datum::timestamp_nanos() for nanosecond timestamp predicates to preserve
# full precision. This allows predicates to be correctly pushed down to Iceberg.

# Create test table with timestamp column
statement ok
CREATE TABLE default.default.test_timestamp_table (id INT NOT NULL, ts TIMESTAMP)

# Insert test data with timestamps
# We use CAST to convert string timestamps to proper timestamp values
query I
INSERT INTO default.default.test_timestamp_table
VALUES
  (1, CAST('2023-01-01 00:00:00' AS TIMESTAMP)),
  (2, CAST('2023-01-05 12:30:00' AS TIMESTAMP)),
  (3, CAST('2023-01-10 15:45:30' AS TIMESTAMP)),
  (4, CAST('2023-01-15 09:00:00' AS TIMESTAMP)),
  (5, CAST('2023-01-20 18:20:10' AS TIMESTAMP))
----
5

# Verify timestamp equality predicate IS pushed down
query TT
EXPLAIN SELECT * FROM default.default.test_timestamp_table WHERE ts = CAST('2023-01-05 12:30:00' AS TIMESTAMP)
----
logical_plan
01)Filter: default.default.test_timestamp_table.ts = TimestampNanosecond(1672921800000000000, None)
02)--TableScan: default.default.test_timestamp_table projection=[id, ts], partial_filters=[default.default.test_timestamp_table.ts = TimestampNanosecond(1672921800000000000, None)]
physical_plan
01)FilterExec: ts@1 = 1672921800000000000
02)--RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=1
03)----CooperativeExec
04)------IcebergTableScan projection:[id,ts] predicate:[ts = 2023-01-05 12:30:00]

# Verify timestamp equality filtering works
query I?
SELECT * FROM default.default.test_timestamp_table WHERE ts = CAST('2023-01-05 12:30:00' AS TIMESTAMP)
----
2 2023-01-05T12:30:00

# Verify timestamp greater than predicate IS pushed down
query TT
EXPLAIN SELECT * FROM default.default.test_timestamp_table WHERE ts > CAST('2023-01-10 00:00:00' AS TIMESTAMP)
----
logical_plan
01)Filter: default.default.test_timestamp_table.ts > TimestampNanosecond(1673308800000000000, None)
02)--TableScan: default.default.test_timestamp_table projection=[id, ts], partial_filters=[default.default.test_timestamp_table.ts > TimestampNanosecond(1673308800000000000, None)]
physical_plan
01)FilterExec: ts@1 > 1673308800000000000
02)--RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=1
03)----CooperativeExec
04)------IcebergTableScan projection:[id,ts] predicate:[ts > 2023-01-10 00:00:00]

# Verify timestamp greater than filtering
query I? rowsort
SELECT * FROM default.default.test_timestamp_table WHERE ts > CAST('2023-01-10 00:00:00' AS TIMESTAMP)
----
3 2023-01-10T15:45:30
4 2023-01-15T09:00:00
5 2023-01-20T18:20:10

# Test timestamp less than or equal filtering
query I? rowsort
SELECT * FROM default.default.test_timestamp_table WHERE ts <= CAST('2023-01-05 12:30:00' AS TIMESTAMP)
----
1 2023-01-01T00:00:00
2 2023-01-05T12:30:00

# Verify timestamp range predicate (AND of two comparisons) IS pushed down
query TT
EXPLAIN SELECT * FROM default.default.test_timestamp_table
WHERE ts >= CAST('2023-01-05 00:00:00' AS TIMESTAMP)
  AND ts <= CAST('2023-01-15 23:59:59' AS TIMESTAMP)
----
logical_plan
01)Filter: default.default.test_timestamp_table.ts >= TimestampNanosecond(1672876800000000000, None) AND default.default.test_timestamp_table.ts <= TimestampNanosecond(1673827199000000000, None)
02)--TableScan: default.default.test_timestamp_table projection=[id, ts], partial_filters=[default.default.test_timestamp_table.ts >= TimestampNanosecond(1672876800000000000, None), default.default.test_timestamp_table.ts <= TimestampNanosecond(1673827199000000000, None)]
physical_plan
01)FilterExec: ts@1 >= 1672876800000000000 AND ts@1 <= 1673827199000000000
02)--RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=1
03)----CooperativeExec
04)------IcebergTableScan projection:[id,ts] predicate:[(ts >= 2023-01-05 00:00:00) AND (ts <= 2023-01-15 23:59:59)]

# Test timestamp range predicate filtering
query I? rowsort
SELECT * FROM default.default.test_timestamp_table
WHERE ts >= CAST('2023-01-05 00:00:00' AS TIMESTAMP)
  AND ts <= CAST('2023-01-15 23:59:59' AS TIMESTAMP)
----
2 2023-01-05T12:30:00
3 2023-01-10T15:45:30
4 2023-01-15T09:00:00

# Test timestamp predicate combined with other predicates
query I? rowsort
SELECT * FROM default.default.test_timestamp_table
WHERE ts >= CAST('2023-01-10 00:00:00' AS TIMESTAMP) AND id < 5
----
3 2023-01-10T15:45:30
4 2023-01-15T09:00:00

# Test timestamp NOT EQUAL predicate
query I? rowsort
SELECT * FROM default.default.test_timestamp_table WHERE ts != CAST('2023-01-05 12:30:00' AS TIMESTAMP)
----
1 2023-01-01T00:00:00
3 2023-01-10T15:45:30
4 2023-01-15T09:00:00
5 2023-01-20T18:20:10

# Test timestamp less than filtering
query I? rowsort
SELECT * FROM default.default.test_timestamp_table WHERE ts < CAST('2023-01-05 00:00:00' AS TIMESTAMP)
----
1 2023-01-01T00:00:00

# Clean up: Drop the test table
statement ok
DROP TABLE default.default.test_timestamp_table

# ============================================================================
# Test timestamp predicate pushdown with different precisions
# ============================================================================

# Test with TIMESTAMP(6) - microsecond precision
statement ok
CREATE TABLE default.default.test_timestamp_micros (id INT NOT NULL, ts TIMESTAMP(6))

query I
INSERT INTO default.default.test_timestamp_micros
VALUES
  (1, CAST('2023-01-01 00:00:00' AS TIMESTAMP)),
  (2, CAST('2023-01-05 12:30:00' AS TIMESTAMP))
----
2

# Verify microsecond timestamp predicate is pushed down
query TT
EXPLAIN SELECT * FROM default.default.test_timestamp_micros WHERE ts > CAST('2023-01-01 00:00:00' AS TIMESTAMP)
----
logical_plan
01)Filter: default.default.test_timestamp_micros.ts > TimestampMicrosecond(1672531200000000, None)
02)--TableScan: default.default.test_timestamp_micros projection=[id, ts], partial_filters=[default.default.test_timestamp_micros.ts > TimestampMicrosecond(1672531200000000, None)]
physical_plan
01)FilterExec: ts@1 > 1672531200000000
02)--RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=1
03)----CooperativeExec
04)------IcebergTableScan projection:[id,ts] predicate:[ts > 2023-01-01 00:00:00]

query I?
SELECT * FROM default.default.test_timestamp_micros WHERE ts > CAST('2023-01-01 00:00:00' AS TIMESTAMP)
----
2 2023-01-05T12:30:00

statement ok
DROP TABLE default.default.test_timestamp_micros

# Test with TIMESTAMP(3) - millisecond precision
# This should fail because Iceberg doesn't support millisecond precision
statement error DataFusion error: External error: DataInvalid => Unsupported Arrow data type: Timestamp\(ms\)
CREATE TABLE default.default.test_timestamp_millis (id INT NOT NULL, ts TIMESTAMP(3))

# Test with TIMESTAMP(0) - second precision
# This should fail because Iceberg doesn't support second precision
statement error DataFusion error: External error: DataInvalid => Unsupported Arrow data type: Timestamp\(s\)
CREATE TABLE default.default.test_timestamp_seconds (id INT NOT NULL, ts TIMESTAMP(0))
