package mail

import (
	"context"
	"errors"
	"net/http"
	"strings"

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

	"github.com/ultisuite/ulti-backend/internal/api/apiresponse"
	"github.com/ultisuite/ulti-backend/internal/api/apivalidate"
	"github.com/ultisuite/ulti-backend/internal/api/middleware"
	mailimap "github.com/ultisuite/ulti-backend/internal/mail/imap"
)

// AccountSyncTrigger runs on-demand IMAP maintenance for owned mail accounts.
type AccountSyncTrigger interface {
	SyncAccountForUser(ctx context.Context, externalID, accountID string) error
	ForceSyncAccountForUser(ctx context.Context, externalID, accountID string) error
	RefetchAccountBodiesForUser(ctx context.Context, externalID, accountID string) (mailimap.RefetchBodiesResult, error)
	ReindexMessageAttachments(ctx context.Context, externalID, messageID string) error
}

func (h *Handler) ResanitizeAccountBodies(w http.ResponseWriter, r *http.Request) {
	claims := middleware.ClaimsFromContext(r.Context())
	accountID := chi.URLParam(r, "accountID")
	if d := validateAccountUUID(accountID); d != nil {
		apivalidate.WriteNotFound(w, r, "not found")
		return
	}

	if h.accountSync != nil {
		result, err := h.accountSync.RefetchAccountBodiesForUser(r.Context(), claims.Sub, accountID)
		if err != nil {
			if errors.Is(err, ErrAccountNotFound) || strings.Contains(err.Error(), "account not found") {
				apivalidate.WriteNotFound(w, r, "not found")
				return
			}
			h.logger.Error("refetch account bodies", "account_id", accountID, "error", err)
			apivalidate.WriteInternal(w, r)
			return
		}
		apiresponse.WriteJSON(w, http.StatusOK, map[string]int{
			"scanned": result.Scanned,
			"updated": result.Updated,
		})
		return
	}

	result, err := h.svc.ResanitizeAccountBodies(r.Context(), claims.Sub, accountID)
	if err != nil {
		if errors.Is(err, ErrAccountNotFound) {
			apivalidate.WriteNotFound(w, r, "not found")
			return
		}
		h.logger.Error("resanitize account bodies", "account_id", accountID, "error", err)
		apivalidate.WriteInternal(w, r)
		return
	}

	apiresponse.WriteJSON(w, http.StatusOK, result)
}

func (h *Handler) SyncAccountNow(w http.ResponseWriter, r *http.Request) {
	claims := middleware.ClaimsFromContext(r.Context())
	accountID := chi.URLParam(r, "accountID")
	if d := validateAccountUUID(accountID); d != nil {
		apivalidate.WriteNotFound(w, r, "not found")
		return
	}
	if h.accountSync == nil {
		apiresponse.WriteError(w, r, http.StatusServiceUnavailable, "sync_unavailable", "mail sync is not configured", nil)
		return
	}

	if _, err := h.svc.GetAccount(r.Context(), claims.Sub, accountID); err != nil {
		if errors.Is(err, ErrNotFound) {
			apivalidate.WriteNotFound(w, r, "not found")
			return
		}
		h.logger.Error("load account for sync", "account_id", accountID, "error", err)
		apivalidate.WriteInternal(w, r)
		return
	}

	force := r.URL.Query().Get("force") == "true"
	var syncErr error
	if force {
		syncErr = h.accountSync.ForceSyncAccountForUser(r.Context(), claims.Sub, accountID)
	} else {
		syncErr = h.accountSync.SyncAccountForUser(r.Context(), claims.Sub, accountID)
	}
	if syncErr != nil {
		h.logger.Error("sync account", "account_id", accountID, "force", force, "error", syncErr)
		apiresponse.WriteError(w, r, http.StatusBadGateway, "sync_failed", "imap sync failed", nil)
		return
	}

	apiresponse.WriteJSON(w, http.StatusOK, map[string]string{"status": "ok"})
}
