package handlers

import (
	"encoding/json"
	"net/http"
	"strings"

	"github.com/sirupsen/logrus"
	"markdown-editor-backend/storage"
)

// Handler contains HTTP handlers for the API
type Handler struct {
	storage *storage.Storage
	log     *logrus.Logger
}

// New creates a new Handler instance
func New(storage *storage.Storage, log *logrus.Logger) *Handler {
	return &Handler{
		storage: storage,
		log:     log,
	}
}

// FileRequest represents a request body for file operations
type FileRequest struct {
	Name    string `json:"name"`
	Content string `json:"content"`
}

// FileResponse represents a file response
type FileResponse struct {
	Name    string `json:"name"`
	Content string `json:"content,omitempty"`
}

// ErrorResponse represents an error response
type ErrorResponse struct {
	Error string `json:"error"`
}

// FilesHandler handles list and create operations
func (h *Handler) FilesHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		h.listFiles(w, r)
	case http.MethodPost:
		h.createFile(w, r)
	default:
		h.sendError(w, http.StatusMethodNotAllowed, "method not allowed")
	}
}

// FileHandler handles get, update, and delete operations for a specific file
func (h *Handler) FileHandler(w http.ResponseWriter, r *http.Request) {
	// Extract filename from URL path
	path := strings.TrimPrefix(r.URL.Path, "/api/files/")
	if path == "" {
		h.sendError(w, http.StatusBadRequest, "filename required")
		return
	}

	name := strings.TrimSuffix(path, ".md")

	switch r.Method {
	case http.MethodGet:
		h.getFile(w, r, name)
	case http.MethodPut:
		h.updateFile(w, r, name)
	case http.MethodDelete:
		h.deleteFile(w, r, name)
	default:
		h.sendError(w, http.StatusMethodNotAllowed, "method not allowed")
	}
}

func (h *Handler) listFiles(w http.ResponseWriter, r *http.Request) {
	h.log.Debug("Handling list files request")

	files, err := h.storage.List()
	if err != nil {
		h.log.WithError(err).Error("Failed to list files")
		h.sendError(w, http.StatusInternalServerError, "failed to list files")
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(files)
}

func (h *Handler) createFile(w http.ResponseWriter, r *http.Request) {
	h.log.Debug("Handling create file request")

	var req FileRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		h.log.WithError(err).Warn("Invalid request body")
		h.sendError(w, http.StatusBadRequest, "invalid request body")
		return
	}

	if req.Name == "" {
		h.sendError(w, http.StatusBadRequest, "name is required")
		return
	}

	if err := h.storage.Save(req.Name, req.Content); err != nil {
		h.log.WithError(err).Error("Failed to create file")
		h.sendError(w, http.StatusInternalServerError, "failed to create file")
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)
	json.NewEncoder(w).Encode(FileResponse{Name: req.Name, Content: req.Content})
}

func (h *Handler) getFile(w http.ResponseWriter, r *http.Request, name string) {
	h.log.WithField("name", name).Debug("Handling get file request")

	content, err := h.storage.Get(name)
	if err != nil {
		if err.Error() == "file not found" {
			h.sendError(w, http.StatusNotFound, "file not found")
			return
		}
		h.log.WithError(err).Error("Failed to get file")
		h.sendError(w, http.StatusInternalServerError, "failed to get file")
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(FileResponse{Name: name, Content: content})
}

func (h *Handler) updateFile(w http.ResponseWriter, r *http.Request, name string) {
	h.log.WithField("name", name).Debug("Handling update file request")

	var req FileRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		h.log.WithError(err).Warn("Invalid request body")
		h.sendError(w, http.StatusBadRequest, "invalid request body")
		return
	}

	if err := h.storage.Save(name, req.Content); err != nil {
		h.log.WithError(err).Error("Failed to update file")
		h.sendError(w, http.StatusInternalServerError, "failed to update file")
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(FileResponse{Name: name, Content: req.Content})
}

func (h *Handler) deleteFile(w http.ResponseWriter, r *http.Request, name string) {
	h.log.WithField("name", name).Debug("Handling delete file request")

	if err := h.storage.Delete(name); err != nil {
		if err.Error() == "file not found" {
			h.sendError(w, http.StatusNotFound, "file not found")
			return
		}
		h.log.WithError(err).Error("Failed to delete file")
		h.sendError(w, http.StatusInternalServerError, "failed to delete file")
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

func (h *Handler) sendError(w http.ResponseWriter, status int, message string) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	json.NewEncoder(w).Encode(ErrorResponse{Error: message})
}
