package filemanager

import (
	"encoding/json"
	"log"

	"github.com/nats-io/nats.go"
)

// HandleNatsRequest is the NATS message handler for the file manager command
// subject (corrosion.{license_id}.files.cmd). It deserialises the request,
// routes to the correct FileManager operation, and calls msg.Respond with a
// NatsResponse JSON payload — either success with data or a structured error.
func (fm *FileManager) HandleNatsRequest(msg *nats.Msg) {
	var req NatsRequest
	if err := json.Unmarshal(msg.Data, &req); err != nil {
		log.Printf("filemanager: invalid NATS request payload: %v", err)
		respondError(msg, "invalid request: "+err.Error())
		return
	}

	log.Printf("filemanager: handling %s path=%q", req.Func, req.Path)

	switch req.Func {

	// -----------------------------------------------------------------------
	// Directory listing
	// -----------------------------------------------------------------------
	case FuncList:
		result, err := fm.List(req.Path)
		if err != nil {
			respondError(msg, err.Error())
			return
		}
		respondJSON(msg, result)

	// -----------------------------------------------------------------------
	// Delete
	// -----------------------------------------------------------------------
	case FuncDelete:
		result, err := fm.Delete(req.Path, req.Items)
		if err != nil {
			respondError(msg, err.Error())
			return
		}
		respondJSON(msg, result)

	// -----------------------------------------------------------------------
	// Rename — req.Name holds the new basename
	// -----------------------------------------------------------------------
	case FuncRename:
		if len(req.Items) == 0 {
			respondError(msg, "rename requires at least one item")
			return
		}
		result, err := fm.Rename(req.Path, req.Items[0], req.Name)
		if err != nil {
			respondError(msg, err.Error())
			return
		}
		respondJSON(msg, result)

	// -----------------------------------------------------------------------
	// Copy
	// -----------------------------------------------------------------------
	case FuncCopy:
		if req.Destination == "" {
			respondError(msg, "copy requires a destination path")
			return
		}
		result, err := fm.Copy(req.Path, req.Items, req.Destination)
		if err != nil {
			respondError(msg, err.Error())
			return
		}
		respondJSON(msg, result)

	// -----------------------------------------------------------------------
	// Move
	// -----------------------------------------------------------------------
	case FuncMove:
		if req.Destination == "" {
			respondError(msg, "move requires a destination path")
			return
		}
		result, err := fm.Move(req.Path, req.Items, req.Destination)
		if err != nil {
			respondError(msg, err.Error())
			return
		}
		respondJSON(msg, result)

	// -----------------------------------------------------------------------
	// Create directory
	// -----------------------------------------------------------------------
	case FuncCreateFolder:
		if req.Name == "" {
			respondError(msg, "mkdir requires a folder name")
			return
		}
		result, err := fm.CreateFolder(req.Path, req.Name)
		if err != nil {
			respondError(msg, err.Error())
			return
		}
		respondJSON(msg, result)

	// -----------------------------------------------------------------------
	// Create empty file
	// -----------------------------------------------------------------------
	case FuncCreateFile:
		if req.Name == "" {
			respondError(msg, "mkfile requires a file name")
			return
		}
		result, err := fm.CreateFile(req.Path, req.Name)
		if err != nil {
			respondError(msg, err.Error())
			return
		}
		respondJSON(msg, result)

	// -----------------------------------------------------------------------
	// Search
	// -----------------------------------------------------------------------
	case FuncSearch:
		result, err := fm.Search(req.Path, req.Filter)
		if err != nil {
			respondError(msg, err.Error())
			return
		}
		respondJSON(msg, result)

	// -----------------------------------------------------------------------
	// Preview / read file content (VueFinder uses "fm_preview" for text files)
	// -----------------------------------------------------------------------
	case FuncPreview:
		content, err := fm.GetContent(req.Path)
		if err != nil {
			respondError(msg, err.Error())
			return
		}
		respondJSON(msg, map[string]string{"content": content})

	// -----------------------------------------------------------------------
	// Save file content
	// -----------------------------------------------------------------------
	case FuncSave:
		if err := fm.SaveContent(req.Path, req.Content); err != nil {
			respondError(msg, err.Error())
			return
		}
		respondJSON(msg, map[string]string{"status": "saved"})

	// -----------------------------------------------------------------------
	// Upload — content arrives as a base64-encoded string
	// -----------------------------------------------------------------------
	case FuncUpload:
		if req.Filename == "" {
			respondError(msg, "upload requires a filename")
			return
		}
		data, err := DecodeBase64(req.Content)
		if err != nil {
			respondError(msg, err.Error())
			return
		}
		result, err := fm.Upload(req.Path, req.Filename, data)
		if err != nil {
			respondError(msg, err.Error())
			return
		}
		respondJSON(msg, result)

	// -----------------------------------------------------------------------
	// Unknown function
	// -----------------------------------------------------------------------
	default:
		log.Printf("filemanager: unknown function %q", req.Func)
		respondError(msg, "unknown function: "+req.Func)
	}
}

// ---------------------------------------------------------------------------
// Response helpers
// ---------------------------------------------------------------------------

// respondJSON sends a successful NatsResponse wrapping data.
func respondJSON(msg *nats.Msg, data interface{}) {
	resp := NatsResponse{Success: true, Data: data}
	bytes, err := json.Marshal(resp)
	if err != nil {
		log.Printf("filemanager: failed to marshal success response: %v", err)
		respondError(msg, "internal: failed to marshal response")
		return
	}
	if err := msg.Respond(bytes); err != nil {
		log.Printf("filemanager: failed to send response: %v", err)
	}
}

// respondError sends a failed NatsResponse with the given error message.
func respondError(msg *nats.Msg, errMsg string) {
	resp := NatsResponse{Success: false, Error: errMsg}
	bytes, _ := json.Marshal(resp)
	if err := msg.Respond(bytes); err != nil {
		log.Printf("filemanager: failed to send error response: %v", err)
	}
}
