// Code generated by go2proto. DO NOT EDIT.

package cron

import "fmt"
import "encoding"
import destpb "github.com/block/ftl/backend/protos/xyz/block/ftl/cron/v1"
import "google.golang.org/protobuf/types/known/timestamppb"
import "google.golang.org/protobuf/types/known/durationpb"
import "github.com/alecthomas/errors"
import "github.com/alecthomas/types/optional"
import "github.com/alecthomas/types/result"

import "time"

var _ fmt.Stringer
var _ = timestamppb.Timestamp{}
var _ = durationpb.Duration{}

// protoSlice converts a slice of values to a slice of protobuf values.
func protoSlice[P any, T interface{ ToProto() P }](values []T) []P {
	out := make([]P, len(values))
	for i, v := range values {
		out[i] = v.ToProto()
	}
	return out
}

func protoMust[T any](v T, err error) T {
	if err != nil {
		panic(err)
	}
	return v
}

func sliceMap[T any, U any](values []T, f func(T) U) []U {
	out := make([]U, len(values))
	for i, v := range values {
		out[i] = f(v)
	}
	return out
}

func sliceMapR[T any, U any](values []T, f func(T) result.Result[U]) result.Result[[]U] {
	if len(values) == 0 {
		return result.Ok[[]U](nil)
	}
	out := make([]U, len(values))
	for i, v := range values {
		r := f(v)
		if r.Err() != nil {
			return result.Err[[]U](r.Err())
		}
		out[i], _ = r.Get()
	}
	return result.Ok[[]U](out)
}

func mapValues[K comparable, V, U any](m map[K]V, f func(V) U) map[K]U {
	out := make(map[K]U, len(m))
	for k, v := range m {
		out[k] = f(v)
	}
	return out
}

func mapValuesR[K comparable, V, U any](m map[K]V, f func(V) result.Result[U]) result.Result[map[K]U] {
	out := make(map[K]U, len(m))
	for k, v := range m {
		r := f(v)
		if r.Err() != nil {
			return result.Err[map[K]U](r.Err())
		}
		val, _ := r.Get()
		out[k] = val
	}
	return result.Ok[map[K]U](out)
}

func orZero[T any](v *T) T {
	if v == nil {
		return *new(T)
	}
	return *v
}

func orZeroR[T any](v result.Result[*T]) result.Result[T] {
	if v.Err() != nil {
		return result.Err[T](v.Err())
	}
	r, _ := v.Get()
	return result.Ok[T](orZero(r))
}

func ptr[T any](o T) *T {
	return &o
}

func ptrR[T any](o result.Result[T]) result.Result[*T] {
	if o.Err() != nil {
		return result.Err[*T](o.Err())
	}
	r, _ := o.Get()
	return result.Ok[*T](ptr(r))
}

func fromPtr[T any](v *T) T {
	if v == nil {
		return *new(T)
	}
	return *v
}

func fromPtrR[T any](v result.Result[*T]) result.Result[T] {
	if v.Err() != nil {
		return result.Err[T](v.Err())
	}
	r, _ := v.Get()
	return result.Ok[T](fromPtr(r))
}

func optionalR[T any](r result.Result[*T]) result.Result[optional.Option[T]] {
	if r.Err() != nil {
		return result.Err[optional.Option[T]](r.Err())
	}
	v, _ := r.Get()
	return result.Ok[optional.Option[T]](optional.Ptr(v))
}

func optionalRPtr[T any](r result.Result[*T]) result.Result[optional.Option[*T]] {
	if r.Err() != nil {
		return result.Err[optional.Option[*T]](r.Err())
	}
	v, _ := r.Get()
	return result.Ok[optional.Option[*T]](optional.Zero(v))
}

func setNil[T, O any](v *T, o *O) *T {
	if o == nil {
		return nil
	}
	return v
}

func setNilR[T, O any](v result.Result[*T], o *O) result.Result[*T] {
	if v.Err() != nil {
		return v
	}
	r, _ := v.Get()
	return result.Ok[*T](setNil(r, o))
}

type binaryUnmarshallable[T any] interface {
	*T
	encoding.BinaryUnmarshaler
}

type textUnmarshallable[T any] interface {
	*T
	encoding.TextUnmarshaler
}

func unmarshallBinary[T any, TPtr binaryUnmarshallable[T]](v []byte, f TPtr) result.Result[*T] {
	var to T
	toptr := (TPtr)(&to)

	err := toptr.UnmarshalBinary(v)
	if err != nil {
		return result.Err[*T](err)
	}
	return result.Ok[*T](&to)
}

func unmarshallText[T any, TPtr textUnmarshallable[T]](v []byte, f TPtr) result.Result[*T] {
	var to T
	toptr := (TPtr)(&to)

	err := toptr.UnmarshalText(v)
	if err != nil {
		return result.Err[*T](err)
	}
	return result.Ok[*T](&to)
}

func (x *CronState) ToProto() *destpb.CronState {
	if x == nil {
		return nil
	}
	return &destpb.CronState{
		LastExecutions: mapValues(x.LastExecutions, func(x time.Time) *timestamppb.Timestamp { return timestamppb.New(x) }),
		NextExecutions: mapValues(x.NextExecutions, func(x time.Time) *timestamppb.Timestamp { return timestamppb.New(x) }),
	}
}

func CronStateFromProto(v *destpb.CronState) (out *CronState, err error) {
	if v == nil {
		return nil, nil
	}

	out = &CronState{}
	if out.LastExecutions, err = mapValuesR(v.LastExecutions, func(v *timestamppb.Timestamp) result.Result[time.Time] {
		return orZeroR(result.From(setNil(ptr(v.AsTime()), v), nil))
	}).Result(); err != nil {
		return nil, errors.Wrap(err, "LastExecutions")
	}
	if out.NextExecutions, err = mapValuesR(v.NextExecutions, func(v *timestamppb.Timestamp) result.Result[time.Time] {
		return orZeroR(result.From(setNil(ptr(v.AsTime()), v), nil))
	}).Result(); err != nil {
		return nil, errors.Wrap(err, "NextExecutions")
	}
	return out, nil
}
