package api

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

	"archivmail/internal/audit"
	"archivmail/internal/storage"
)

// handleListSavedSearches returns all saved searches for the current user.
// GET /api/searches/saved
func (s *Server) handleListSavedSearches(w http.ResponseWriter, r *http.Request) {
	sess := sessionFromCtx(r.Context())
	tenantID := tenantFromCtx(r.Context())
	if tenantID == nil {
		writeError(w, http.StatusBadRequest, "tenant context required")
		return
	}

	searches, err := s.store.ListSavedSearches(r.Context(), sess.UserID, *tenantID)
	if err != nil {
		s.logger.Error("saved_searches: list failed", "err", err)
		writeError(w, http.StatusInternalServerError, "failed to list saved searches")
		return
	}
	if searches == nil {
		searches = []storage.SavedSearch{}
	}
	writeJSON(w, http.StatusOK, searches)
}

// handleCreateSavedSearch creates a new saved search.
// POST /api/searches/saved
// Body: {"name": "...", "query": {...}}
func (s *Server) handleCreateSavedSearch(w http.ResponseWriter, r *http.Request) {
	sess := sessionFromCtx(r.Context())
	tenantID := tenantFromCtx(r.Context())
	if tenantID == nil {
		writeError(w, http.StatusBadRequest, "tenant context required")
		return
	}

	var body struct {
		Name  string          `json:"name"`
		Query json.RawMessage `json:"query"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		writeError(w, http.StatusBadRequest, "invalid JSON body")
		return
	}

	name := strings.TrimSpace(body.Name)
	if name == "" {
		writeError(w, http.StatusBadRequest, "name is required")
		return
	}
	if len(name) > 200 {
		writeError(w, http.StatusBadRequest, "name too long (max 200 chars)")
		return
	}
	if len(body.Query) == 0 {
		writeError(w, http.StatusBadRequest, "query is required")
		return
	}
	// Validate that query is valid JSON object
	var tmp map[string]interface{}
	if err := json.Unmarshal(body.Query, &tmp); err != nil {
		writeError(w, http.StatusBadRequest, "query must be a valid JSON object")
		return
	}

	ss, err := s.store.CreateSavedSearch(r.Context(), sess.UserID, *tenantID, name, []byte(body.Query))
	if err != nil {
		s.logger.Error("saved_searches: create failed", "err", err)
		writeError(w, http.StatusInternalServerError, "failed to create saved search")
		return
	}

	s.audlog.Log(audit.Entry{
		EventType: "saved_search_create",
		Username:  sess.Username,
		TenantID:  sess.TenantID,
		IPAddress: s.remoteIP(r),
		Detail:    fmt.Sprintf("saved search id=%d name=%q", ss.ID, name),
		Success:   true,
	})

	writeJSON(w, http.StatusCreated, ss)
}

// handleDeleteSavedSearch deletes a saved search by ID.
// DELETE /api/searches/saved/{id}
func (s *Server) handleDeleteSavedSearch(w http.ResponseWriter, r *http.Request) {
	sess := sessionFromCtx(r.Context())
	tenantID := tenantFromCtx(r.Context())
	if tenantID == nil {
		writeError(w, http.StatusBadRequest, "tenant context required")
		return
	}

	idStr := r.PathValue("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil || id <= 0 {
		writeError(w, http.StatusBadRequest, "invalid id")
		return
	}

	err = s.store.DeleteSavedSearch(r.Context(), id, sess.UserID, *tenantID)
	if err != nil {
		if strings.Contains(err.Error(), "not found or not owned") {
			writeError(w, http.StatusForbidden, "saved search not found or access denied")
			return
		}
		s.logger.Error("saved_searches: delete failed", "err", err)
		writeError(w, http.StatusInternalServerError, "failed to delete saved search")
		return
	}

	s.audlog.Log(audit.Entry{
		EventType: "saved_search_delete",
		Username:  sess.Username,
		TenantID:  sess.TenantID,
		IPAddress: s.remoteIP(r),
		Detail:    fmt.Sprintf("saved search id=%d", id),
		Success:   true,
	})

	writeJSON(w, http.StatusOK, map[string]string{"status": "deleted"})
}
