/*
 * 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 (
	"io"
	"net/http"

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

const zeroContentLength = "0"

func (hand *Handler) FileInfo(rctx *router.Context) {

	filepath, _ := rctx.GetSubpath("filepath")
	params := &operator.FileInfoParams{
		Filepath: filepath,
	}
	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightReadFiles, "")
	if err != nil {
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	if !opEnable {
		rctx.SetStatus(http.StatusMethodNotAllowed)
		return
	}
	// Execution of the operation
	ctx := rctx.GetContext()
	code, res, err := hand.oper.FileInfo(ctx, uuid.UUID(operatorID), params)
	if err != nil {
		hand.logg.Errorf("FileInfo error: %v", err)
		rctx.SetStatus(code)
		return
	}
	rctx.SetHeader("Content-Collection", res.ContentCollection)
	rctx.SetHeader("Content-Name", res.ContentName)
	rctx.SetHeader("Content-Type", res.ContentType)
	rctx.SetHeader("Content-Size", res.ContentSize)
	rctx.SetHeader("Content-Digest", res.ContentDigest)

	rctx.SetHeader("Content-CreatedAt", res.ContentCreatedAt)
	rctx.SetHeader("Content-CreatedBy", string(res.ContentCreatedBy))
	rctx.SetHeader("Content-UpdatedAt", res.ContentUpdatedAt)
	rctx.SetHeader("Content-UpdatedBy", string(res.ContentUpdatedBy))

	rctx.SetHeader("Content-Length", zeroContentLength)
	rctx.SetStatus(code)
}

func (hand *Handler) PutFile(rctx *router.Context) {
	contentSize := rctx.GetHeader("Content-Size")
	contentType := rctx.GetHeader("Content-Type")
	filepath, _ := rctx.GetSubpath("filepath")

	params := &operator.PutFileParams{
		Filepath:    filepath,
		ContentType: contentType,
		ContentSize: contentSize,
		Source:      rctx.Request.Body,
	}
	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightWriteFiles, "")
	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.PutFile(ctx, uuid.UUID(operatorID), params)
	if err != nil {
		hand.logg.Errorf("PutFile error: %v", err)
		rctx.SetStatus(code)
		return
	}
	rctx.SetStatus(code)
}

func (hand *Handler) GetFile(rctx *router.Context) {

	filepath, _ := rctx.GetSubpath("filepath")
	params := &operator.GetFileParams{
		Filepath: filepath,
	}
	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightReadFiles, "")
	if err != nil {
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	if !opEnable {
		rctx.SetStatus(http.StatusMethodNotAllowed)
		return
	}
	// Execution of the operation
	ctx := rctx.GetContext()
	code, res, err := hand.oper.GetFile(ctx, uuid.UUID(operatorID), params)
	if err != nil {
		hand.logg.Errorf("PutFile error: %v", err)
		rctx.SetStatus(code)
		return
	}

	rctx.SetHeader("Content-Type", res.ContentType)
	rctx.SetHeader("Content-Size", res.ContentSize)
	rctx.SetHeader("Content-Digest", res.ContentDigest)
	rctx.SetHeader("Content-Length", res.ContentSize)

	rctx.SetHeader("Content-CreatedAt", res.ContentCreatedAt)
	rctx.SetHeader("Content-CreatedBy", string(res.ContentCreatedBy))
	rctx.SetHeader("Content-UpdatedAt", res.ContentUpdatedAt)
	rctx.SetHeader("Content-UpdatedBy", string(res.ContentUpdatedBy))

	rctx.SetStatus(code)

	if res.Source != nil {
		defer res.Source.Close()
		_, err = io.Copy(rctx.Writer, res.Source)
		if err != nil {
			hand.logg.Errorf("GetFile error: %v", err)
			return
		}
	}
}

func (hand *Handler) DeleteFile(rctx *router.Context) {

	filepath, _ := rctx.GetSubpath("filepath")
	params := &operator.DeleteFileParams{
		Filepath: filepath,
	}
	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightWriteFiles, "")
	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.DeleteFile(ctx, uuid.UUID(operatorID), params)
	if err != nil {
		hand.logg.Errorf("DeleteFIle error: %v", err)
	}

	rctx.SetStatus(code)
}

func (hand *Handler) ListFiles(rctx *router.Context) {

	filepath, _ := rctx.GetSubpath("filepath")
	if filepath == "" {
		filepath = "/"
	}
	params := &operator.ListFilesParams{
		Filepath: filepath,
	}
	err := rctx.BindQuery(params)
	if err != nil {
		hand.logg.Errorf("ListFiles binding error: %v", err)
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}

	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightReadFiles, "")
	if err != nil {
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	if !opEnable {
		rctx.SetStatus(http.StatusMethodNotAllowed)
		return
	}
	// Execution of the operation
	ctx := rctx.GetContext()
	code, res, err := hand.oper.ListFiles(ctx, uuid.UUID(operatorID), params)
	if err != nil {
		hand.logg.Errorf("ListFiles error: %v", err)
		rctx.SetStatus(code)
		return
	}
	rctx.SendJSON(code, res.Files)
}

func (hand *Handler) ListCollections(rctx *router.Context) {

	cpath, _ := rctx.GetSubpath("path")
	if cpath == "" {
		cpath = "/"
	}
	params := &operator.ListCollectionsParams{
		Path: cpath,
	}
	err := rctx.BindQuery(params)
	if err != nil {
		hand.logg.Errorf("ListCollections binding error: %v", err)
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightReadFiles, "")
	if err != nil {
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	if !opEnable {
		rctx.SetStatus(http.StatusMethodNotAllowed)
		return
	}
	// Execution of the operation
	ctx := rctx.GetContext()
	code, res, err := hand.oper.ListCollections(ctx, uuid.UUID(operatorID), params)
	if err != nil {
		hand.logg.Errorf("ListCollections error: %v", err)
		rctx.SetStatus(code)
		return
	}
	rctx.SendJSON(code, res.Collections)
}

func (hand *Handler) DeleteCollection(rctx *router.Context) {

	cpath, _ := rctx.GetSubpath("path")
	if cpath == "" {
		cpath = "/"
	}
	params := &operator.DeleteColletionParams{
		Path: cpath,
	}
	err := rctx.BindQuery(params)
	if err != nil {
		hand.logg.Errorf("DeleteColletion binding error: %v", err)
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}

	// Rigth checking
	operatorID, _ := rctx.GetString(userTag)
	opEnable, err := hand.CheckRight(rctx.Ctx, uuid.UUID(operatorID), term.RightReadFiles, "")
	if err != nil {
		rctx.SetStatus(http.StatusInternalServerError)
		return
	}
	if !opEnable {
		rctx.SetStatus(http.StatusMethodNotAllowed)
		return
	}
	// Execution of the operation
	ctx := rctx.GetContext()
	code, res, err := hand.oper.DeleteColletion(ctx, uuid.UUID(operatorID), params)
	if err != nil {
		hand.logg.Errorf("DeleteColletion error: %v", err)
		rctx.SetStatus(code)
		return
	}
	rctx.SendJSON(code, res.Files)
}
