package handlers_test

import (
	"context"
	"net/http"
	"reflect"
	"testing"
	"time"

	"otaupdate/handlers"
	"otaupdate/services"

	"github.com/fiskerinc/cloud-services/pkg/common"
	th "github.com/fiskerinc/cloud-services/pkg/testhelper"
	"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
	"github.com/pkg/errors"
)

type CHMockConn struct {
	query string
	args  []interface{}
	ret   interface{}
}

func (c *CHMockConn) Select(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
	if query != c.query {
		return errors.Errorf("queries are not equal: %s != %s", query, c.query)
	}

	if len(args) != len(c.args) {
		return errors.Errorf("args are not of the same length, %d != %d", len(args), len(c.args))
	}

	for i := 0; i < len(args); i++ {
		if !reflect.DeepEqual(args[i], c.args[i]) {
			return errors.Errorf("args[i] != mock.args[i], %v, %v", args[i], c.args[i])
		}
	}

	if reflect.TypeOf(dest) != reflect.TypeOf(c.ret) {
		return errors.Errorf("type of dest is not equal to the needed return type, %v, %v", dest, c.ret)
	}

	valOfPtr := c.ret.(*[]common.ClickHouseSignal)

	val := reflect.ValueOf(dest)
	val.Elem().Set(reflect.ValueOf(*valOfPtr))

	return nil
}

func (c *CHMockConn) PrepareBatch(ctx context.Context, query string) (driver.Batch, error) {
	return nil, nil
}

func (c *CHMockConn) AsyncInsert(ctx context.Context, query string, wait bool) error {
	return nil
}

func (c *CHMockConn) QueryRow(ctx context.Context, query string, args ...interface{}) driver.Row {
	return nil
}

func (c *CHMockConn) Query(ctx context.Context, query string, args ...interface{}) (driver.Rows, error) {
	return nil, nil
}

func (c *CHMockConn) Exec(ctx context.Context, query string, args ...interface{}) error {
	return nil
}

func floatPointer(num float64) *float64 {
	return &num
}

func TestHandleVehicleSignals(t *testing.T) {
	services.SetClickhouseConn(&CHMockConn{
		query: handlers.SqlCHSelectSignals,
		args:  []interface{}{"2D4FV48T95H646760", time.UnixMilli(0), 20},
		ret: &[]common.ClickHouseSignal{{
			Timestamp: time.Date(2022, 9, 1, 0, 0, 0, 0, time.UTC),
			Name:      "Signal",
			Value:     floatPointer(123),
		}},
	})

	tests := []th.BasicHttpTest{
		{
			Name:             "Invalid vin parameter",
			Request:          th.MakeTestRequest(http.MethodGet, "http://example.com/cansignals/TESTVIN123", nil),
			ExpectedStatus:   http.StatusBadRequest,
			ExpectedResponse: `{"message":"vin 'TESTVIN123' invalid","error":"Bad Request"}`,
		},
		{
			Name:             "Valid data",
			Request:          th.MakeTestRequest(http.MethodGet, "http://example.com/cansignals/2D4FV48T95H646760", nil),
			ExpectedStatus:   http.StatusOK,
			ExpectedResponse: `{"data":[{"timestamp":"2022-09-01T00:00:00Z","name":"Signal","value":123}]}`,
		},
	}

	th.RunParamHttpTests(t, tests, handlers.HandleVehiclesSignals, "/cansignals/:vin")
}
