/*
 * Copyright 2026 Oleg Borodin <onborodin@gmail.com>
 */
package imageoper

import (
	"context"
	"fmt"
	"net/http"

	"mstore/pkg/descr"

	ocidigest "github.com/opencontainers/go-digest"
)

type DeleteManifestParams struct {
	Name      string
	Reference string
}
type DeleteManifestResult struct{}

func (oper *Operator) DeleteManifest(ctx context.Context, params *DeleteManifestParams) (*DeleteManifestResult, int, error) {
	var err error
	res := &DeleteManifestResult{}

	if params.Name == "" {
		err = fmt.Errorf("Empty name")
		return res, http.StatusBadRequest, err
	}
	if params.Reference == "" {
		err = fmt.Errorf("Empty reference")
		return res, http.StatusBadRequest, err
	}

	resName := params.Name
	oper.iLock.WaitAndLock(resName)
	defer oper.iLock.Done(resName)

	var exists bool
	var reference string

	mandescr := descr.Manifest{}

	// Check manifest by digest as name

	digobj, err := ocidigest.Parse(params.Reference)
	if err == nil {
		exists, mandescr, err = oper.mdb.GetManifestByDigest(ctx, params.Name, digobj.String())
		if err != nil {
			return res, http.StatusInternalServerError, err
		}
		if !exists {
			return res, http.StatusNotFound, err
		}
		reference = mandescr.Reference
		err = oper.deleteManifestObjects(ctx, params.Name, reference)
		if err != nil {
			return res, http.StatusInternalServerError, err
		}
	} else {
		/*
			// Check manifest by name and reference
			exists, mandescrs, err := oper.mdb.GetManifestsByReference(ctx, params.Name, params.Reference)
			if err != nil {
				return res, http.StatusInternalServerError, err
			}
			if !exists {
				return res, http.StatusNotFound, err
			}
			reference = params.Reference
			for _, mandescr := range mandescrs {
				reference = mandescr.Reference
				err = oper.deleteManifestObjects(ctx, params.Name, reference)
				if err != nil {
					return res, http.StatusInternalServerError, err
				}
			}
		*/
		// Check manifest by name and reference
		exists, mandescr, err := oper.mdb.GetManifestByReference(ctx, params.Name, params.Reference)
		if err != nil {
			return res, http.StatusInternalServerError, err
		}
		if !exists {
			return res, http.StatusNotFound, err
		}
		err = oper.deleteManifestObjects(ctx, mandescr.Name, mandescr.Reference)
		if err != nil {
			return res, http.StatusInternalServerError, err
		}
	}
	// Get blobs associated with the name
	return res, http.StatusAccepted, err
}

func (oper *Operator) deleteManifestObjects(ctx context.Context, name, reference string) error {
	var err error
	// Get blobs associated with the name
	layers, err := oper.mdb.GetBlobsByReferense(ctx, name, reference)
	if err != nil {
		return err
	}
	for _, blob := range layers {
		// Delete descr record
		err = oper.mdb.DeleteBlobByNameDigest(ctx, blob.Name, blob.Digest)
		if err != nil {
			return err
		}
		// Check blob file
		exists, _, err := oper.store.BlobExists(name, blob.Digest)
		if err != nil {
			return err
		}
		if exists {
			// Check blob usage
			blobUsage, err := oper.mdb.GetBlobUsage(ctx, blob.Name, blob.Digest)
			if err != nil {
				return err
			}
			// Delete if blob useless
			if blobUsage == 0 {
				err = oper.store.DeleteBlob(name, blob.Digest)
				if err != nil {
					return err
				}
			}
		}
	}
	err = oper.mdb.DeleteManifest(ctx, name, reference)
	if err != nil {
		return err
	}
	return err
}
