package progress

import (
	"time"

	"github.com/moby/buildkit/client"
	"github.com/moby/buildkit/identity"
	"github.com/opencontainers/go-digest"
)

type Logger func(*client.SolveStatus)

type SubLogger interface {
	Wrap(name string, fn func() error) error
	Log(stream int, dt []byte)
	SetStatus(*client.VertexStatus)
}

func Wrap(name string, l Logger, fn func(SubLogger) error) (err error) {
	dgst := digest.FromBytes([]byte(identity.NewID()))
	tm := time.Now()
	l(&client.SolveStatus{
		Vertexes: []*client.Vertex{{
			Digest:  dgst,
			Name:    name,
			Started: &tm,
		}},
	})

	defer func() {
		tm2 := time.Now()
		errMsg := ""
		if err != nil {
			errMsg = err.Error()
		}
		l(&client.SolveStatus{
			Vertexes: []*client.Vertex{{
				Digest:    dgst,
				Name:      name,
				Started:   &tm,
				Completed: &tm2,
				Error:     errMsg,
			}},
		})
	}()

	return fn(&subLogger{dgst, l})
}

type subLogger struct {
	dgst   digest.Digest
	logger Logger
}

func (sl *subLogger) Wrap(name string, fn func() error) (err error) {
	tm := time.Now()
	sl.logger(&client.SolveStatus{
		Statuses: []*client.VertexStatus{{
			Vertex:    sl.dgst,
			ID:        name,
			Timestamp: time.Now(),
			Started:   &tm,
		}},
	})

	defer func() {
		tm2 := time.Now()
		sl.logger(&client.SolveStatus{
			Statuses: []*client.VertexStatus{{
				Vertex:    sl.dgst,
				ID:        name,
				Timestamp: time.Now(),
				Started:   &tm,
				Completed: &tm2,
			}},
		})
	}()

	return fn()
}

func (sl *subLogger) Log(stream int, dt []byte) {
	sl.logger(&client.SolveStatus{
		Logs: []*client.VertexLog{{
			Vertex:    sl.dgst,
			Stream:    stream,
			Data:      dt,
			Timestamp: time.Now(),
		}},
	})
}

func (sl *subLogger) SetStatus(st *client.VertexStatus) {
	st.Vertex = sl.dgst
	sl.logger(&client.SolveStatus{
		Statuses: []*client.VertexStatus{st},
	})
}
