package sq

import (
	"context"
	"database/sql"
	"fmt"
	"github.com/glebarez/go-sqlite"
	"github.com/jmoiron/sqlx"
	"gogs.mikescher.com/BlackForestBytes/goext/langext"
	"gogs.mikescher.com/BlackForestBytes/goext/rfctime"
	"gogs.mikescher.com/BlackForestBytes/goext/tst"
	"os"
	"path/filepath"
	"testing"
	"time"
)

func TestTypeConverter1(t *testing.T) {
	type RequestData struct {
		ID        string    `db:"id"`
		Timestamp time.Time `db:"timestamp"`
	}

	if !langext.InArray("sqlite3", sql.Drivers()) {
		sqlite.RegisterAsSQLITE3()
	}

	ctx := context.Background()

	dbdir := t.TempDir()
	dbfile1 := filepath.Join(dbdir, langext.MustHexUUID()+".sqlite3")

	tst.AssertNoErr(t, os.MkdirAll(dbdir, os.ModePerm))

	url := fmt.Sprintf("file:%s?_pragma=journal_mode(%s)&_pragma=timeout(%d)&_pragma=foreign_keys(%s)&_pragma=busy_timeout(%d)", dbfile1, "DELETE", 1000, "true", 1000)

	xdb := tst.Must(sqlx.Open("sqlite", url))(t)

	db := NewDB(xdb, DBOptions{RegisterDefaultConverter: langext.PTrue})

	_, err := db.Exec(ctx, "CREATE TABLE `requests` ( id TEXT NOT NULL, timestamp INTEGER NOT NULL, PRIMARY KEY (id) ) STRICT", PP{})
	tst.AssertNoErr(t, err)

	_, err = InsertSingle(ctx, db, "requests", RequestData{
		ID:        "001",
		Timestamp: time.Date(2000, 06, 15, 12, 0, 0, 0, time.UTC),
	})
	tst.AssertNoErr(t, err)
}

func TestTypeConverter2(t *testing.T) {

	if !langext.InArray("sqlite3", sql.Drivers()) {
		sqlite.RegisterAsSQLITE3()
	}

	type RequestData struct {
		ID        string                `db:"id"`
		Timestamp rfctime.UnixMilliTime `db:"timestamp"`
	}

	ctx := context.Background()

	dbdir := t.TempDir()
	dbfile1 := filepath.Join(dbdir, langext.MustHexUUID()+".sqlite3")

	tst.AssertNoErr(t, os.MkdirAll(dbdir, os.ModePerm))

	url := fmt.Sprintf("file:%s?_pragma=journal_mode(%s)&_pragma=timeout(%d)&_pragma=foreign_keys(%s)&_pragma=busy_timeout(%d)", dbfile1, "DELETE", 1000, "true", 1000)

	xdb := tst.Must(sqlx.Open("sqlite", url))(t)

	db := NewDB(xdb, DBOptions{RegisterDefaultConverter: langext.PTrue})

	_, err := db.Exec(ctx, "CREATE TABLE `requests` ( id TEXT NOT NULL, timestamp INTEGER NOT NULL, PRIMARY KEY (id) ) STRICT", PP{})
	tst.AssertNoErr(t, err)

	t0 := rfctime.NewUnixMilli(time.Date(2012, 03, 01, 16, 0, 0, 0, time.UTC))

	_, err = InsertSingle(ctx, db, "requests", RequestData{
		ID:        "002",
		Timestamp: t0,
	})
	tst.AssertNoErr(t, err)

	r, err := QuerySingle[RequestData](ctx, db, "SELECT * FROM requests WHERE id = '002'", PP{}, SModeExtended, Safe)
	tst.AssertNoErr(t, err)

	fmt.Printf("%+v\n", r)

	tst.AssertEqual(t, "002", r.ID)
	tst.AssertEqual(t, t0.UnixNano(), r.Timestamp.UnixNano())
}

func TestTypeConverter3(t *testing.T) {

	if !langext.InArray("sqlite3", sql.Drivers()) {
		sqlite.RegisterAsSQLITE3()
	}

	type RequestData struct {
		ID        string                 `db:"id"`
		Timestamp *rfctime.UnixMilliTime `db:"timestamp"`
	}

	ctx := context.Background()

	dbdir := t.TempDir()
	dbfile1 := filepath.Join(dbdir, langext.MustHexUUID()+".sqlite3")

	tst.AssertNoErr(t, os.MkdirAll(dbdir, os.ModePerm))

	url := fmt.Sprintf("file:%s?_pragma=journal_mode(%s)&_pragma=timeout(%d)&_pragma=foreign_keys(%s)&_pragma=busy_timeout(%d)", dbfile1, "DELETE", 1000, "true", 1000)

	xdb := tst.Must(sqlx.Open("sqlite", url))(t)

	db := NewDB(xdb, DBOptions{RegisterDefaultConverter: langext.PTrue})

	_, err := db.Exec(ctx, "CREATE TABLE `requests` ( id TEXT NOT NULL, timestamp INTEGER NULL, PRIMARY KEY (id) ) STRICT", PP{})
	tst.AssertNoErr(t, err)

	t0 := rfctime.NewUnixMilli(time.Date(2012, 03, 01, 16, 0, 0, 0, time.UTC))

	_, err = InsertSingle(ctx, db, "requests", RequestData{
		ID:        "001",
		Timestamp: &t0,
	})
	tst.AssertNoErr(t, err)

	_, err = InsertSingle(ctx, db, "requests", RequestData{
		ID:        "002",
		Timestamp: nil,
	})
	tst.AssertNoErr(t, err)

	{
		r1, err := QuerySingle[RequestData](ctx, db, "SELECT * FROM requests WHERE id = '001'", PP{}, SModeExtended, Safe)
		tst.AssertNoErr(t, err)
		fmt.Printf("%+v\n", r1)
		tst.AssertEqual(t, "001", r1.ID)
		tst.AssertEqual(t, t0.UnixNano(), r1.Timestamp.UnixNano())
	}

	{
		r2, err := QuerySingle[RequestData](ctx, db, "SELECT * FROM requests WHERE id = '002'", PP{}, SModeExtended, Safe)
		tst.AssertNoErr(t, err)
		fmt.Printf("%+v\n", r2)
		tst.AssertEqual(t, "002", r2.ID)
		tst.AssertEqual(t, nil, r2.Timestamp)
	}
}