package client

import (
	"errors"
	"net/http"
	"os"

	dCliCommand "github.com/docker/cli/cli/command"
	dCliConfig "github.com/docker/cli/cli/config"
	dContext "github.com/docker/cli/cli/context"
	dCliContextStore "github.com/docker/cli/cli/context/store"
	dClient "github.com/docker/docker/client"
	"github.com/moby/term"
	"github.com/sirupsen/logrus"
)

func NewClientWithContext(contextURL string) *dClient.Client {
	helper := newConnectionHelper(contextURL)
	httpClient := &http.Client{
		// No tls
		// No proxy
		Transport: &http.Transport{
			DialContext: helper.Dialer,
		},
	}

	var clientOpts []dClient.Opt

	clientOpts = append(clientOpts,
		dClient.WithHTTPClient(httpClient),
		dClient.WithHost(helper.Host),
		dClient.WithDialContext(helper.Dialer),
	)

	// FIXME: Maybe don't have this variable here and load it beforehand
	version := os.Getenv("DOCKER_API_VERSION")

	if version != "" {
		clientOpts = append(clientOpts, dClient.WithVersion(version))
	} else {
		clientOpts = append(clientOpts, dClient.WithAPIVersionNegotiation())
	}

	cl, err := dClient.NewClientWithOpts(clientOpts...)

	if err != nil {
		logrus.Fatalf("unable to create Docker client: %s", err)
	}
	return cl
}

func GetContextEndpoint(ctx dCliContextStore.Metadata) (string, error) {
	// safe to use docker key hardcoded since abra doesn't use k8s... yet...
	endpointmeta, ok := ctx.Endpoints["docker"].(dContext.EndpointMetaBase)
	if !ok {
		err := errors.New("context lacks Docker endpoint")
		return "", err
	}
	return endpointmeta.Host, nil
}

func NewDefaultDockerContextStore() *dCliCommand.ContextStoreWithDefault {
	// Grabbing the stderr from Docker commands
	// Much easier to fit this into the code we are using to replicate docker cli commands
	_, _, stderr := term.StdStreams()
	// TODO: Look into custom docker configs in case users want that
	dockerConfig := dCliConfig.LoadDefaultConfigFile(stderr)
	contextDir := dCliConfig.ContextStoreDir()
	storeConfig := dCliCommand.DefaultContextStoreConfig()
	store := newContextStore(contextDir, storeConfig)

	dockerContextStore := &dCliCommand.ContextStoreWithDefault{
		Store: store,
		Resolver: func() (*dCliCommand.DefaultContext, error) {
			// nil for the Opts because it works without it and its a cli thing
			return dCliCommand.ResolveDefaultContext(nil, dockerConfig, storeConfig, stderr)
		},
	}
	return dockerContextStore
}

func newContextStore(dir string, config dCliContextStore.Config) dCliContextStore.Store {
	return dCliContextStore.New(dir, config)
}