package api

import (
	"encoding/json"
	"io"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gorilla/mux"
	"github.com/sirupsen/logrus"
)

type APIHandler struct {
	dataDir string
	log     *logrus.Logger
}

func NewAPIHandler(dataDir string, log *logrus.Logger) *APIHandler {
	return &APIHandler{
		dataDir: dataDir,
		log:     log,
	}
}

func (h *APIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		h.handleGet(w, r)
	case http.MethodPost:
		h.handlePost(w, r)
	case http.MethodPut:
		h.handlePut(w, r)
	case http.MethodDelete:
		h.handleDelete(w, r)
	default:
		h.writeError(w, http.StatusMethodNotAllowed, "method not allowed")
	}
}

func (h *APIHandler) handleListFiles(w http.ResponseWriter, r *http.Request) {
	h.log.Info("GET request for file listing")

	files, err := os.ReadDir(h.dataDir)
	if err != nil {
		h.log.Errorf("Error reading data directory: %v", err)
		h.writeError(w, http.StatusInternalServerError, "failed to list files")
		return
	}

	filenames := []string{}
	for _, file := range files {
		if !file.IsDir() && filepath.Ext(file.Name()) == ".md" {
			filenames = append(filenames, file.Name())
		}
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string][]string{"files": filenames})
}

func (h *APIHandler) handleGet(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	filename := vars["filename"]

	if filename == "" {
		h.handleListFiles(w, r)
		return
	}

	h.log.Infof("GET request for file: %s", filename)

	filepath := filepath.Join(h.dataDir, filename)
	content, err := os.ReadFile(filepath)
	if err != nil {
		h.log.Errorf("Error reading file %s: %v", filename, err)
		h.writeError(w, http.StatusNotFound, "file not found")
		return
	}

	w.Header().Set("Content-Type", "text/plain")
	w.Write(content)
}

func (h *APIHandler) handlePost(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	filename := vars["filename"]

	h.log.Infof("POST request for file: %s", filename)

	filepath := filepath.Join(h.dataDir, filename)
	content, err := io.ReadAll(r.Body)
	if err != nil {
		h.log.Errorf("Error reading request body: %v", err)
		h.writeError(w, http.StatusBadRequest, "invalid request body")
		return
	}

	if err := os.WriteFile(filepath, content, 0644); err != nil {
		h.log.Errorf("Error writing file %s: %v", filename, err)
		h.writeError(w, http.StatusInternalServerError, "failed to create file")
		return
	}

	w.WriteHeader(http.StatusCreated)
}

func (h *APIHandler) handlePut(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	filename := vars["filename"]

	h.log.Infof("PUT request for file: %s", filename)

	filepath := filepath.Join(h.dataDir, filename)
	content, err := io.ReadAll(r.Body)
	if err != nil {
		h.log.Errorf("Error reading request body: %v", err)
		h.writeError(w, http.StatusBadRequest, "invalid request body")
		return
	}

	if err := os.WriteFile(filepath, content, 0644); err != nil {
		h.log.Errorf("Error writing file %s: %v", filename, err)
		h.writeError(w, http.StatusInternalServerError, "failed to update file")
		return
	}

	w.WriteHeader(http.StatusOK)
}

func (h *APIHandler) handleDelete(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	filename := vars["filename"]

	h.log.Infof("DELETE request for file: %s", filename)

	filepath := filepath.Join(h.dataDir, filename)
	if err := os.Remove(filepath); err != nil {
		h.log.Errorf("Error deleting file %s: %v", filename, err)
		h.writeError(w, http.StatusNotFound, "file not found")
		return
	}

	w.WriteHeader(http.StatusNoContent)
}

func (h *APIHandler) writeError(w http.ResponseWriter, statusCode int, message string) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(statusCode)
	json.NewEncoder(w).Encode(map[string]string{"error": message})
}
