package admin

import (
	"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/drive"
	"github.com/ultisuite/ulti-backend/internal/api/middleware"
)

func (h *Handler) registerDriveAdminRoutes(r chi.Router, read, write func(http.Handler) http.Handler) {
	r.With(read).Get("/drive/org-folders", h.ListDriveOrgFolders)
	r.With(write).Post("/drive/org-folders", h.CreateDriveOrgFolder)
	r.With(write).Put("/drive/org-folders/{folderID}", h.UpdateDriveOrgFolder)
	r.With(write).Delete("/drive/org-folders/{folderID}", h.DeleteDriveOrgFolder)
	r.With(write).Post("/drive/org-folders/sync", h.SyncDriveOrgFolders)
	h.registerDriveOrgMountRoutes(r, read, write)
}

func (h *Handler) driveService() *drive.Service {
	return drive.NewService(h.svc.nc, nil, h.svc.db)
}

func (h *Handler) ListDriveOrgFolders(w http.ResponseWriter, r *http.Request) {
	svc := h.driveService()
	folders, err := svc.ListOrgFoldersAdmin(r.Context())
	if err != nil {
		h.logger.Error("list drive org folders", "error", err)
		apivalidate.WriteInternal(w, r)
		return
	}
	apiresponse.WriteJSON(w, http.StatusOK, map[string]any{"folders": folders})
}

func (h *Handler) CreateDriveOrgFolder(w http.ResponseWriter, r *http.Request) {
	claims := middleware.ClaimsFromContext(r.Context())
	svc := h.driveService()
	var req struct {
		OrgSlug    string `json:"org_slug"`
		MountPoint string `json:"mount_point"`
		QuotaBytes *int64 `json:"quota_bytes"`
	}
	if err := apivalidate.DecodeJSON(w, r, 32<<10, &req); err != nil {
		return
	}
	createdBy := ""
	if claims != nil {
		createdBy = claims.Email
	}
	folder, err := svc.CreateOrgFolder(r.Context(), drive.CreateOrgFolderParams{
		OrgSlug:    req.OrgSlug,
		MountPoint: req.MountPoint,
		QuotaBytes: req.QuotaBytes,
		CreatedBy:  createdBy,
	})
	if err != nil {
		writeDriveAdminError(w, r, err)
		return
	}
	apiresponse.WriteJSON(w, http.StatusCreated, folder)
}

func (h *Handler) UpdateDriveOrgFolder(w http.ResponseWriter, r *http.Request) {
	svc := h.driveService()
	var req struct {
		MountPoint string `json:"mount_point"`
		QuotaBytes *int64 `json:"quota_bytes"`
	}
	if err := apivalidate.DecodeJSON(w, r, 32<<10, &req); err != nil {
		return
	}
	folder, err := svc.UpdateOrgFolder(r.Context(), chi.URLParam(r, "folderID"), req.MountPoint, req.QuotaBytes)
	if err != nil {
		writeDriveAdminError(w, r, err)
		return
	}
	apiresponse.WriteJSON(w, http.StatusOK, folder)
}

func (h *Handler) DeleteDriveOrgFolder(w http.ResponseWriter, r *http.Request) {
	svc := h.driveService()
	if err := svc.DeleteOrgFolder(r.Context(), chi.URLParam(r, "folderID")); err != nil {
		writeDriveAdminError(w, r, err)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}

func (h *Handler) SyncDriveOrgFolders(w http.ResponseWriter, r *http.Request) {
	claims := middleware.ClaimsFromContext(r.Context())
	svc := h.driveService()
	var req struct {
		OrgSlugs []string `json:"org_slugs"`
	}
	if err := apivalidate.DecodeJSON(w, r, 32<<10, &req); err != nil {
		return
	}
	createdBy := ""
	if claims != nil {
		createdBy = claims.Email
	}
	folders, err := svc.SyncOrgFolders(r.Context(), req.OrgSlugs, createdBy)
	if err != nil {
		writeDriveAdminError(w, r, err)
		return
	}
	apiresponse.WriteJSON(w, http.StatusOK, map[string]any{"folders": folders})
}

func writeDriveAdminError(w http.ResponseWriter, r *http.Request, err error) {
	switch {
	case err == drive.ErrNotFound:
		apivalidate.WriteNotFound(w, r, "not found")
	case err == drive.ErrConflict:
		apiresponse.WriteError(w, r, http.StatusConflict, "drive.conflict", "resource conflict", nil)
	case err == drive.ErrInvalid:
		apiresponse.WriteError(w, r, http.StatusBadRequest, apiresponse.CodeInvalidRequest, "invalid request body", nil)
	default:
		if strings.Contains(err.Error(), "not found") {
			apivalidate.WriteNotFound(w, r, "not found")
			return
		}
		apivalidate.WriteInternal(w, r)
	}
}
