package containerd

import (
	"context"
	"encoding/json"

	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/mount"
	"github.com/docker/docker/container"
	"github.com/docker/docker/pkg/archive"
	"github.com/google/uuid"
	"github.com/opencontainers/image-spec/identity"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/sirupsen/logrus"
)

func (i *ImageService) Changes(ctx context.Context, container *container.Container) ([]archive.Change, error) {
	cs := i.client.ContentStore()

	imageManifest, err := getContainerImageManifest(container)
	if err != nil {
		return nil, err
	}

	imageManifestBytes, err := content.ReadBlob(ctx, cs, imageManifest)
	if err != nil {
		return nil, err
	}
	var manifest ocispec.Manifest
	if err := json.Unmarshal(imageManifestBytes, &manifest); err != nil {
		return nil, err
	}

	imageConfigBytes, err := content.ReadBlob(ctx, cs, manifest.Config)
	if err != nil {
		return nil, err
	}
	var image ocispec.Image
	if err := json.Unmarshal(imageConfigBytes, &image); err != nil {
		return nil, err
	}

	rnd, err := uuid.NewRandom()
	if err != nil {
		return nil, err
	}

	snapshotter := i.client.SnapshotService(container.Driver)

	diffIDs := image.RootFS.DiffIDs
	parent, err := snapshotter.View(ctx, rnd.String(), identity.ChainID(diffIDs).String())
	if err != nil {
		return nil, err
	}
	defer func() {
		if err := snapshotter.Remove(ctx, rnd.String()); err != nil {
			logrus.WithError(err).WithField("key", rnd.String()).Warn("remove temporary snapshot")
		}
	}()

	var changes []archive.Change
	err = i.PerformWithBaseFS(ctx, container, func(containerRootfs string) error {
		return mount.WithReadonlyTempMount(ctx, parent, func(parentRootfs string) error {
			changes, err = archive.ChangesDirs(containerRootfs, parentRootfs)
			return err
		})
	})
	return changes, err
}
