package csbi

import (
	"bufio"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"path/filepath"
	"time"

	spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
	"github.com/docker/docker/pkg/archive"
	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"
)

// nolint
type ErrorLine struct {
	Error       string      `json:"error"`
	ErrorDetail ErrorDetail `json:"errorDetail"`
}

// nolint
type ErrorDetail struct {
	Message string `json:"message"`
}

func buildImage(d Deployment, dockerClient *client.Client) (err error) {
	labels := prometheus.Labels{"type": spb.Type_TYPE_CONTAINERISED.String()}
	start := promStartHook(labels, buildsTotal)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*300)
	defer cancel()

	p := filepath.Join(d.ID.String(), "/")
	tar, err := archive.TarWithOptions(p, &archive.TarOptions{})
	if err != nil {
		return err
	}

	opts := types.ImageBuildOptions{
		Dockerfile: "Dockerfile",
		Tags:       []string{d.Name},
		Remove:     true,
	}
	res, err := dockerClient.ImageBuild(ctx, tar, opts)
	if err != nil {
		return err
	}
	defer func() {
		if ferr := res.Body.Close(); ferr != nil {
			fErrString := ferr.Error()
			err = fmt.Errorf("InternalError=%w DeferError=%+s", err, fErrString)
		}
	}()

	err = printImageBody(res.Body)
	if err != nil {
		return err
	}
	promEndHook(labels, start, buildDurationSecondsTotal, buildDurationSeconds)
	return nil
}

func printImageBody(rd io.Reader) error {
	var lastLine string

	scanner := bufio.NewScanner(rd)
	for scanner.Scan() {
		lastLine = scanner.Text()
		fmt.Println(scanner.Text())
	}

	errLine := &ErrorLine{}
	err := json.Unmarshal([]byte(lastLine), errLine)
	if errLine.Error != "" {
		return errors.New(errLine.Error)
	} else if err != nil {
		log.Error(err)
	}

	return scanner.Err()
}
