package report

import (
	"context"

	"code.justin.tv/eventbus/controlplane/e2e/internal/e2eutil"
	"go.uber.org/zap/zapcore"
)

// Implementation of report.Message that uses the context
// from when the message was fired to provide reporting information
// NOTE: normally it isn't great to store context in a struct,
// but in this case we want to collect potentially many errors
// and save them for reporting all at the end. In this case,
// it makes sense to store context objects in a struct to meet
// this use case.
type ContextMessage struct {
	ctx context.Context
	msg string
}

func MessageFromContext(ctx context.Context, msg string) *ContextMessage {
	return &ContextMessage{
		ctx: ctx,
		msg: msg,
	}
}

func (c *ContextMessage) Message() string   { return c.msg }
func (c *ContextMessage) Phase() string     { return e2eutil.Phase(c.ctx) }
func (c *ContextMessage) TestPath() string  { return e2eutil.TestPath(c.ctx) }
func (c *ContextMessage) SuiteName() string { return e2eutil.SuiteName(c.ctx) }
func (c *ContextMessage) JobID() string     { return e2eutil.JobID(c.ctx) }

func (c *ContextMessage) MarshalLogObject(enc zapcore.ObjectEncoder) error {
	enc.AddString("phase", c.Phase())
	enc.AddString("testPath", c.TestPath())
	enc.AddString("suiteName", c.SuiteName())
	enc.AddString("jobID", c.JobID())
	return nil
}

// Implementation of report.Error that builds on the above
// ContextMessage to also provide information about errors
type ContextError struct {
	*ContextMessage
	err error
}

func ErrorFromContext(ctx context.Context, msg string, err error) *ContextError {
	return &ContextError{
		ContextMessage: MessageFromContext(ctx, msg),
		err:            err,
	}
}

func (c *ContextError) Error() error { return c.err }
