//go:build ignore

package main

import (
	"bytes"
	"fmt"
	"go/format"
	"log"
	"os"
)

var funcs = []struct {
	name, expr string
}{
	{"dayofweek", "int64(nano.Ts(v).Time().Weekday())"},
	{"day", "int64(nano.Ts(v).Time().Day())"},
	{"dow", "int64(nano.Ts(v).Time().Weekday())"},
	{"hour", "int64(nano.Ts(v).Time().Hour())"},
	{"microseconds", "int64(nano.Ts(v).Time().Second()*1e6 + nano.Ts(v).Time().Nanosecond()/1e3)"},
	{"milliseconds", "int64(nano.Ts(v).Time().Second()*1e3 + nano.Ts(v).Time().Nanosecond()/1e6)"},
	{"minute", "int64(nano.Ts(v).Time().Minute())"},
	{"month", "int64(nano.Ts(v).Time().Month())"},
	{"second", "int64(nano.Ts(v).Time().Second())"},
	{"year", "int64(nano.Ts(v).Time().Year())"},
}

const datePartSwitch = `switch vec := vec.(type) {
case *vector.View:
	index := vec.Index
	inner := vec.Any.(*vector.Int)
	out := make([]int64, len(index))
	for i, idx := range index {
		v := inner.Values[idx]
		out[i] = %[1]s
	}
	return vector.NewInt(super.TypeInt64, out, inner.Nulls.Pick(index))
case *vector.Const:
	v := vec.Value().Int()
	val := super.NewInt64(%[1]s)
	return vector.NewConst(val, vec.Len(), vec.Nulls)
case *vector.Dict:
	out := %[2]s(vec.Any).(*vector.Int)
	return vector.NewDict(out, vec.Index, vec.Counts, vec.Nulls)
case *vector.Int:
	out := make([]int64, vec.Len())
	for i, v := range vec.Values {
		out[i] = %[1]s
	}
	return vector.NewInt(super.TypeInt64, out, vec.Nulls)
default:
	panic(vec)
}
`

func main() {
	var buf bytes.Buffer
	fmt.Fprintln(&buf, "// Code generated by gendatepart.go. DO NOT EDIT.")
	fmt.Fprintln(&buf)
	fmt.Fprintln(&buf, "package function")
	fmt.Fprintln(&buf, "import (")
	fmt.Fprintln(&buf, `"github.com/brimdata/super/vector"`)
	fmt.Fprintln(&buf, `"github.com/brimdata/super"`)
	fmt.Fprintln(&buf, `"github.com/brimdata/super/pkg/nano"`)
	fmt.Fprintln(&buf, ")")
	for _, fn := range funcs {
		fmt.Fprintf(&buf, "func %s(vec vector.Any) vector.Any {\n", funcName(fn.name))
		fmt.Fprintf(&buf, datePartSwitch, fn.expr, funcName(fn.name))
		fmt.Fprintf(&buf, "}\n\n")
	}
	buf.WriteString("var datePartFuncs = map[string]func(vector.Any)vector.Any {\n")
	for _, fn := range funcs {
		fmt.Fprintf(&buf, "%q: %s,\n", fn.name, funcName(fn.name))
	}
	buf.WriteString("}\n")
	out, formatErr := format.Source(buf.Bytes())
	if formatErr != nil {
		// Write unformatted source so we can find the error.
		out = buf.Bytes()
	}
	const fileName = "datepartfuncs.go"
	if err := os.WriteFile(fileName, out, 0644); err != nil {
		log.Fatal(err)
	}
	if formatErr != nil {
		log.Fatal(fileName, ":", formatErr)
	}
}

func funcName(s string) string {
	return fmt.Sprintf("date_time_%s", s)
}
