package handlers

import (
	"encoding/json"
	"net/http"

	"xorm.io/xorm"

	"github.com/forgeo/forgebucket/internal/api/middleware"
	"github.com/forgeo/forgebucket/internal/models"
)

type LFSHandler struct{ db *xorm.Engine }

func NewLFSHandler(db *xorm.Engine) *LFSHandler { return &LFSHandler{db: db} }

func (h *LFSHandler) resolveRepo(w http.ResponseWriter, r *http.Request) (*models.Repository, bool) {
	return resolveRepo(h.db, w, r)
}

func (h *LFSHandler) canManage(repo *models.Repository, callerID int64) bool {
	if callerID == repo.OwnerID {
		return true
	}
	var m models.RepoMember
	found, _ := h.db.Where("repo_id = ? AND user_id = ? AND permission = 'admin'", repo.ID, callerID).Get(&m)
	return found
}

func (h *LFSHandler) Get(w http.ResponseWriter, r *http.Request) {
	repo, ok := h.resolveRepo(w, r)
	if !ok {
		return
	}

	var s models.RepoLFSSettings
	h.db.Where("repo_id = ?", repo.ID).Get(&s)
	jsonOK(w, lfsResponse(repo.ID, &s))
}

func (h *LFSHandler) Update(w http.ResponseWriter, r *http.Request) {
	repo, ok := h.resolveRepo(w, r)
	if !ok {
		return
	}
	callerID, _ := middleware.UserIDFromContext(r.Context())
	if !h.canManage(repo, callerID) {
		jsonError(w, "forbidden", http.StatusForbidden)
		return
	}

	var body struct {
		Enabled        *bool  `json:"enabled"`
		LockingEnabled *bool  `json:"lockingEnabled"`
		MaxFileSizeMB  *int64 `json:"maxFileSizeMB"`
	}
	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
		jsonError(w, "invalid request body", http.StatusBadRequest)
		return
	}

	var s models.RepoLFSSettings
	found, err := h.db.Where("repo_id = ?", repo.ID).Get(&s)
	if err != nil {
		jsonError(w, "database error: "+err.Error(), http.StatusInternalServerError)
		return
	}
	s.RepoID = repo.ID

	if body.Enabled != nil {
		s.Enabled = *body.Enabled
	}
	if body.LockingEnabled != nil {
		s.LockingEnabled = *body.LockingEnabled
	}
	if body.MaxFileSizeMB != nil {
		s.MaxFileSizeMB = *body.MaxFileSizeMB
	}

	if found {
		if _, err := h.db.ID(s.ID).Cols("enabled", "locking_enabled", "max_file_size_mb").Update(&s); err != nil {
			jsonError(w, "could not update LFS settings", http.StatusInternalServerError)
			return
		}
	} else {
		if _, err := h.db.Insert(&s); err != nil {
			jsonError(w, "could not save LFS settings", http.StatusInternalServerError)
			return
		}
	}

	jsonOK(w, lfsResponse(repo.ID, &s))
}

type lfsSettingsResponse struct {
	Enabled        bool  `json:"enabled"`
	LockingEnabled bool  `json:"lockingEnabled"`
	MaxFileSizeMB  int64 `json:"maxFileSizeMB"`
}

func lfsResponse(_ int64, s *models.RepoLFSSettings) lfsSettingsResponse {
	return lfsSettingsResponse{
		Enabled:        s.Enabled,
		LockingEnabled: s.LockingEnabled,
		MaxFileSizeMB:  s.MaxFileSizeMB,
	}
}
