package localinlinecache

import (
	"context"
	"encoding/json"
	"time"

	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/remotes/docker"
	distreference "github.com/docker/distribution/reference"
	imagestore "github.com/docker/docker/image"
	"github.com/docker/docker/reference"
	"github.com/moby/buildkit/cache/remotecache"
	registryremotecache "github.com/moby/buildkit/cache/remotecache/registry"
	v1 "github.com/moby/buildkit/cache/remotecache/v1"
	"github.com/moby/buildkit/session"
	"github.com/moby/buildkit/solver"
	"github.com/moby/buildkit/worker"
	digest "github.com/opencontainers/go-digest"
	specs "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

func init() {
	// See https://github.com/moby/buildkit/pull/1993.
	v1.EmptyLayerRemovalSupported = false
}

// ResolveCacheImporterFunc returns a resolver function for local inline cache
func ResolveCacheImporterFunc(sm *session.Manager, resolverFunc docker.RegistryHosts, cs content.Store, rs reference.Store, is imagestore.Store) remotecache.ResolveCacheImporterFunc {

	upstream := registryremotecache.ResolveCacheImporterFunc(sm, cs, resolverFunc)

	return func(ctx context.Context, group session.Group, attrs map[string]string) (remotecache.Importer, specs.Descriptor, error) {
		if dt, err := tryImportLocal(rs, is, attrs["ref"]); err == nil {
			return newLocalImporter(dt), specs.Descriptor{}, nil
		}
		return upstream(ctx, group, attrs)
	}
}

func tryImportLocal(rs reference.Store, is imagestore.Store, refStr string) ([]byte, error) {
	ref, err := distreference.ParseNormalizedNamed(refStr)
	if err != nil {
		return nil, err
	}
	dgst, err := rs.Get(ref)
	if err != nil {
		return nil, err
	}
	img, err := is.Get(imagestore.ID(dgst))
	if err != nil {
		return nil, err
	}

	return img.RawJSON(), nil
}

func newLocalImporter(dt []byte) remotecache.Importer {
	return &localImporter{dt: dt}
}

type localImporter struct {
	dt []byte
}

func (li *localImporter) Resolve(ctx context.Context, _ specs.Descriptor, id string, w worker.Worker) (solver.CacheManager, error) {
	cc := v1.NewCacheChains()
	if err := li.importInlineCache(ctx, li.dt, cc); err != nil {
		return nil, err
	}

	keysStorage, resultStorage, err := v1.NewCacheKeyStorage(cc, w)
	if err != nil {
		return nil, err
	}
	return solver.NewCacheManager(id, keysStorage, resultStorage), nil
}

func (li *localImporter) importInlineCache(ctx context.Context, dt []byte, cc solver.CacheExporterTarget) error {
	var img image

	if err := json.Unmarshal(dt, &img); err != nil {
		return err
	}

	if img.Cache == nil {
		return nil
	}

	var config v1.CacheConfig
	if err := json.Unmarshal(img.Cache, &config.Records); err != nil {
		return err
	}

	createdDates, createdMsg, err := parseCreatedLayerInfo(img)
	if err != nil {
		return err
	}

	layers := v1.DescriptorProvider{}
	for i, diffID := range img.Rootfs.DiffIDs {
		dgst := digest.Digest(diffID.String())
		desc := specs.Descriptor{
			Digest:      dgst,
			Size:        -1,
			MediaType:   images.MediaTypeDockerSchema2Layer,
			Annotations: map[string]string{},
		}
		if createdAt := createdDates[i]; createdAt != "" {
			desc.Annotations["buildkit/createdat"] = createdAt
		}
		if createdBy := createdMsg[i]; createdBy != "" {
			desc.Annotations["buildkit/description"] = createdBy
		}
		desc.Annotations["containerd.io/uncompressed"] = img.Rootfs.DiffIDs[i].String()
		layers[dgst] = v1.DescriptorProviderPair{
			Descriptor: desc,
			Provider:   &emptyProvider{},
		}
		config.Layers = append(config.Layers, v1.CacheLayer{
			Blob:        dgst,
			ParentIndex: i - 1,
		})
	}

	return v1.ParseConfig(config, layers, cc)
}

type image struct {
	Rootfs struct {
		DiffIDs []digest.Digest `json:"diff_ids"`
	} `json:"rootfs"`
	Cache   []byte `json:"moby.buildkit.cache.v0"`
	History []struct {
		Created    *time.Time `json:"created,omitempty"`
		CreatedBy  string     `json:"created_by,omitempty"`
		EmptyLayer bool       `json:"empty_layer,omitempty"`
	} `json:"history,omitempty"`
}

func parseCreatedLayerInfo(img image) ([]string, []string, error) {
	dates := make([]string, 0, len(img.Rootfs.DiffIDs))
	createdBy := make([]string, 0, len(img.Rootfs.DiffIDs))
	for _, h := range img.History {
		if !h.EmptyLayer {
			str := ""
			if h.Created != nil {
				dt, err := h.Created.MarshalText()
				if err != nil {
					return nil, nil, err
				}
				str = string(dt)
			}
			dates = append(dates, str)
			createdBy = append(createdBy, h.CreatedBy)
		}
	}
	return dates, createdBy, nil
}

type emptyProvider struct {
}

func (p *emptyProvider) ReaderAt(ctx context.Context, dec specs.Descriptor) (content.ReaderAt, error) {
	return nil, errors.Errorf("ReaderAt not implemented for empty provider")
}
