package api

import (
	"errors"
	"net/http"

	"github.com/go-chi/chi/v5"

	"github.com/alexei/docker-watcher/internal/store"
)

// volumeRequest is the expected JSON body for creating/updating a volume.
type volumeRequest struct {
	Source string `json:"source"`
	Target string `json:"target"`
	Mode   string `json:"mode"`
}

// listVolumes handles GET /api/projects/{id}/volumes.
func (s *Server) listVolumes(w http.ResponseWriter, r *http.Request) {
	projectID := chi.URLParam(r, "id")

	// Verify project exists.
	if _, err := s.store.GetProjectByID(projectID); err != nil {
		if errors.Is(err, store.ErrNotFound) {
			respondNotFound(w, "project")
			return
		}
		respondError(w, http.StatusInternalServerError, "failed to get project: "+err.Error())
		return
	}

	vols, err := s.store.GetVolumesByProjectID(projectID)
	if err != nil {
		respondError(w, http.StatusInternalServerError, "failed to list volumes: "+err.Error())
		return
	}

	respondJSON(w, http.StatusOK, vols)
}

// createVolume handles POST /api/projects/{id}/volumes.
func (s *Server) createVolume(w http.ResponseWriter, r *http.Request) {
	projectID := chi.URLParam(r, "id")

	// Verify project exists.
	if _, err := s.store.GetProjectByID(projectID); err != nil {
		if errors.Is(err, store.ErrNotFound) {
			respondNotFound(w, "project")
			return
		}
		respondError(w, http.StatusInternalServerError, "failed to get project: "+err.Error())
		return
	}

	var req volumeRequest
	if !decodeJSON(w, r, &req) {
		return
	}

	if req.Source == "" {
		respondError(w, http.StatusBadRequest, "source is required")
		return
	}
	if req.Target == "" {
		respondError(w, http.StatusBadRequest, "target is required")
		return
	}
	if req.Mode == "" {
		req.Mode = "shared"
	}
	if req.Mode != "shared" && req.Mode != "isolated" {
		respondError(w, http.StatusBadRequest, "mode must be 'shared' or 'isolated'")
		return
	}

	vol, err := s.store.CreateVolume(store.Volume{
		ProjectID: projectID,
		Source:    req.Source,
		Target:   req.Target,
		Mode:     req.Mode,
	})
	if err != nil {
		respondError(w, http.StatusInternalServerError, "failed to create volume: "+err.Error())
		return
	}
	respondJSON(w, http.StatusCreated, vol)
}

// updateVolume handles PUT /api/projects/{id}/volumes/{volId}.
func (s *Server) updateVolume(w http.ResponseWriter, r *http.Request) {
	volID := chi.URLParam(r, "volId")

	existing, err := s.store.GetVolumeByID(volID)
	if err != nil {
		if errors.Is(err, store.ErrNotFound) {
			respondNotFound(w, "volume")
			return
		}
		respondError(w, http.StatusInternalServerError, "failed to get volume: "+err.Error())
		return
	}

	var req volumeRequest
	if !decodeJSON(w, r, &req) {
		return
	}

	updated := existing
	if req.Source != "" {
		updated.Source = req.Source
	}
	if req.Target != "" {
		updated.Target = req.Target
	}
	if req.Mode != "" {
		if req.Mode != "shared" && req.Mode != "isolated" {
			respondError(w, http.StatusBadRequest, "mode must be 'shared' or 'isolated'")
			return
		}
		updated.Mode = req.Mode
	}

	if err := s.store.UpdateVolume(updated); err != nil {
		respondError(w, http.StatusInternalServerError, "failed to update volume: "+err.Error())
		return
	}
	respondJSON(w, http.StatusOK, updated)
}

// deleteVolume handles DELETE /api/projects/{id}/volumes/{volId}.
func (s *Server) deleteVolume(w http.ResponseWriter, r *http.Request) {
	volID := chi.URLParam(r, "volId")
	if err := s.store.DeleteVolume(volID); err != nil {
		if errors.Is(err, store.ErrNotFound) {
			respondNotFound(w, "volume")
			return
		}
		respondError(w, http.StatusInternalServerError, "failed to delete volume: "+err.Error())
		return
	}
	respondJSON(w, http.StatusOK, map[string]string{"deleted": volID})
}
