//go:build integration
// +build integration

package integration_test

import (
	"context"
	"database/sql"
	"fmt"
	"strings"
	"testing"
	"time"
)

func TestTimestampPrecision(t *testing.T) {
	requireProxy(t)

	session := newSession(t, sessionOptions{disableHostLookup: true})
	keyspace := uniqueKeyspace()
	if err := session.Query(createKeyspaceCQL(keyspace)).Exec(); err != nil {
		t.Fatalf("create keyspace failed: %v", err)
	}
	t.Cleanup(func() {
		_ = session.Query(dropKeyspaceCQL(keyspace)).Exec()
	})

	table := "timestamp_precision"
	create := fmt.Sprintf("CREATE TABLE %s.%s (id int PRIMARY KEY, ts timestamp, t time)", keyspace, table)
	if err := session.Query(create).Exec(); err != nil {
		t.Fatalf("create table failed: %v", err)
	}

	db, err := sql.Open("mysql", mysqlDSN(mysqlCfg))
	if err != nil {
		t.Fatalf("mysql connect failed: %v", err)
	}
	defer db.Close()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	rows, err := db.QueryContext(ctx, `
SELECT column_name, data_type, datetime_precision
FROM information_schema.columns
WHERE table_schema = ? AND table_name = ? AND column_name IN ('ts', 't')`,
		keyspace,
		table,
	)
	if err != nil {
		t.Fatalf("query information_schema failed: %v", err)
	}
	defer rows.Close()

	type colInfo struct {
		dataType  string
		precision sql.NullInt64
	}
	cols := make(map[string]colInfo, 2)
	for rows.Next() {
		var name string
		var info colInfo
		if err := rows.Scan(&name, &info.dataType, &info.precision); err != nil {
			t.Fatalf("scan column info failed: %v", err)
		}
		cols[name] = info
	}
	if err := rows.Err(); err != nil {
		t.Fatalf("iterate column info failed: %v", err)
	}

	checkPrecision := func(name, dataType string) {
		info, ok := cols[name]
		if !ok {
			t.Fatalf("column %q not found in information_schema", name)
		}
		if strings.ToLower(info.dataType) != dataType {
			t.Fatalf("unexpected data type for %s: %s", name, info.dataType)
		}
		if !info.precision.Valid || info.precision.Int64 != 6 {
			t.Fatalf("unexpected precision for %s: %#v", name, info.precision)
		}
	}

	checkPrecision("ts", "datetime")
	checkPrecision("t", "time")

	micro := "2024-06-01 12:34:56.123456"
	insert := fmt.Sprintf("INSERT INTO %s.%s JSON '{\"id\": 1, \"ts\": \"%s\"}'", keyspace, table, micro)
	if err := session.Query(insert).Exec(); err != nil {
		t.Fatalf("insert JSON failed: %v", err)
	}

	var mysqlTS time.Time
	fetchSQL := fmt.Sprintf("SELECT ts FROM `%s`.`%s` WHERE id = 1", keyspace, table)
	if err := db.QueryRowContext(ctx, fetchSQL).Scan(&mysqlTS); err != nil {
		t.Fatalf("mysql fetch failed: %v", err)
	}
	if got := mysqlTS.Format("2006-01-02 15:04:05.000000"); got != micro {
		t.Fatalf("unexpected mysql timestamp: %s", got)
	}

	var cqlTS time.Time
	selectCQL := fmt.Sprintf("SELECT ts FROM %s.%s WHERE id = 1", keyspace, table)
	if err := session.Query(selectCQL).Scan(&cqlTS); err != nil {
		t.Fatalf("select timestamp failed: %v", err)
	}
	if got := cqlTS.UTC().Format("2006-01-02 15:04:05.000"); got != "2024-06-01 12:34:56.123" {
		t.Fatalf("unexpected CQL timestamp: %s", got)
	}
}
