/*
 * Copyright 2026 Oleg Borodin <onborodin@gmail.com>
 *
 * This work is published and licensed under a Creative Commons
 * Attribution-NonCommercial-NoDerivatives 4.0 International License.
 *
 * Distribution of this work is permitted, but commercial use and
 * modifications are strictly prohibited.
 */
package handler

import (
	"net/http"

	"mstore/app/operator"
	"mstore/app/router"
	"mstore/pkg/term"
	"mstore/pkg/uuid"
)

func (hand *Handler) ManifestExists(rctx *router.Context) {
	name, _ := rctx.GetSubpath("name")
	reference, _ := rctx.GetSubpath("reference")

	hand.DumpHeaders("ManigestExists:\n", rctx)

	params := &operator.ManifestExistsParams{
		Name:      name,
		Reference: reference,
	}
	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightReadImages, "")
	if err != nil {
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	if !opEnable {
		rctx.SetStatus(http.StatusMethodNotAllowed)
		return
	}
	// Execution of the operation
	ctx := rctx.GetContext()
	res, code, err := hand.oper.ManifestExists(ctx, params)
	if err != nil {
		hand.logg.Errorf("ManifestExist error: %v", err)
	} else if code == http.StatusOK {
		rctx.SetHeader("Content-Length", res.ContentLength)
		rctx.SetHeader("Content-Type", res.ContentType)
		rctx.SetHeader("Docker-Content-Digest", res.DockerContentDigest)
	}
	rctx.SetStatus(code)
}

// PUT /v2/<name>/manifests/<reference> 201 404
func (hand *Handler) PutManifest(rctx *router.Context) {

	//hand.DumpHeaders("PutManifest headers", rctx)

	contentType := rctx.GetHeader("Content-Type")
	contentLength := rctx.GetHeader("Content-Length")

	name, _ := rctx.GetSubpath("name")
	reference, _ := rctx.GetSubpath("reference")

	params := &operator.PutManifestParams{
		ContentType:   contentType,
		ContentLength: contentLength,
		Name:          name,
		Reference:     reference,
		Reader:        rctx.Request.Body,
	}
	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightWriteImages, "")
	if err != nil {
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	if !opEnable {
		rctx.SetStatus(http.StatusMethodNotAllowed)
		return
	}
	// Execution of the operation
	ctx := rctx.GetContext()
	res, code, err := hand.oper.PutManifest(ctx, params)
	if err != nil {
		hand.logg.Errorf("PutManifest error: %v", err)
	} else {
		rctx.SetHeader("Location", res.Location)
	}
	rctx.SetStatus(code)
}

// GET /v2/<name>/manifests/<reference> 200 404
func (hand *Handler) GetManifest(rctx *router.Context) {
	name, _ := rctx.GetSubpath("name")
	reference, _ := rctx.GetSubpath("reference")

	//hand.DumpHeaders("GetManigest", rctx)

	params := &operator.GetManifestParams{
		Name:      name,
		Reference: reference,
	}
	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightReadImages, "")
	if err != nil {
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	if !opEnable {
		rctx.SetStatus(http.StatusMethodNotAllowed)
		return
	}
	// Execution of the operation
	ctx := rctx.GetContext()
	res, code, err := hand.oper.GetManifest(ctx, params)
	if err != nil {
		hand.logg.Errorf("GetManifest error: %v", err)
		rctx.SetStatus(code)
		return
	}
	if code == http.StatusOK {
		//hand.logg.Debugf("GetManifest type: %s", res.ContentType)
		//hand.logg.Debugf("GetManifest payload: %s", res.Payload)
		rctx.SetHeader("Content-Length", res.ContentLength)
		//rctx.SetHeader("Content-Type", res.ContentType)
		rctx.SetHeader("Docker-Content-Digest", res.DockerContentDigest)
		rctx.SendBytes(code, res.ContentType, []byte(res.Payload))
		return
	}
	rctx.SetStatus(code)
}

// DELETE /v2/<name>/manifests/<reference> 200 404
func (hand *Handler) DeleteManifest(rctx *router.Context) {
	name, _ := rctx.GetSubpath("name")
	reference, _ := rctx.GetSubpath("reference")

	params := &operator.DeleteManifestParams{
		Name:      name,
		Reference: reference,
	}
	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightWriteImages, "")
	if err != nil {
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	if !opEnable {
		rctx.SetStatus(http.StatusMethodNotAllowed)
		return
	}
	// Execution of the operation
	ctx := rctx.GetContext()
	_, code, err := hand.oper.DeleteManifest(ctx, params)
	if err != nil {
		hand.logg.Errorf("DeleteManifest error: %v", err)
	}
	rctx.SetStatus(code)
}

// GET /v2/<name>/referrers/<digest>                              200 404/400
// GET /v2/<name>/referrers/<digest>?artifactType=<artifactType>  200 404/400
func (hand *Handler) GetReferer(rctx *router.Context) {
	name, _ := rctx.GetSubpath("name")
	digest, _ := rctx.GetSubpath("digest")
	params := &operator.GetRefererParams{
		Name:   name,
		Digest: digest,
	}
	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightReadImages, "")
	if err != nil {
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	if !opEnable {
		rctx.SetStatus(http.StatusMethodNotAllowed)
		return
	}
	// Execution of the operation
	res, code, err := hand.oper.GetReferer(rctx.Ctx, params)
	if err != nil {
		hand.logg.Errorf("GetReferer error: %v", err)
	}
	rctx.SendText(code, res.Reference)
}

// GET /v2/<name>/tags/list 200 404
// GET /v2/<name>/tags/list?n=<integer>&last=<integer>
func (hand *Handler) GetTags(rctx *router.Context) {
	name, _ := rctx.GetSubpath("name")
	params := &operator.GetTagsParams{
		Name: name,
	}
	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightReadImages, "")
	if err != nil {
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	if !opEnable {
		rctx.SetStatus(http.StatusMethodNotAllowed)
		return
	}
	// Execution of the operation
	ctx := rctx.GetContext()
	res, code, err := hand.oper.GetTags(ctx, params)
	if err != nil {
		hand.logg.Errorf("GetTags error: %v", err)
	}
	rctx.SendJSON(code, res.TagDescr)
}
