// Package api provides HTTP handlers for camera operations.
package api

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
)

// maxRequestBody is the maximum accepted JSON body size (64KB).
const maxRequestBody = 64 * 1024

// APIError represents a structured API error response.
type APIError struct {
	Error   string `json:"error"`
	Code    int    `json:"code"`
	Details string `json:"details,omitempty"`
}

// validationConstraints defines field-level validation limits.
const (
	maxCameraIDLen     = 64
	maxFriendlyNameLen = 128
	maxModeLen         = 32
	maxResolutionLen   = 32
	minFPS             = 0
	maxFPS             = 240
)

// respondError writes a structured JSON error response.
func respondError(w http.ResponseWriter, status int, msg string, details ...string) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	e := APIError{
		Error: msg,
		Code:  status,
	}
	if len(details) > 0 {
		e.Details = details[0]
	}
	json.NewEncoder(w).Encode(e)
}

// decodeJSONBody reads, limits, and decodes a JSON request body.
// Returns false if validation fails (response already written).
func decodeJSONBody(w http.ResponseWriter, r *http.Request, v interface{}) bool {
	// Validate Content-Type
	ct := r.Header.Get("Content-Type")
	if ct != "" && !strings.HasPrefix(ct, "application/json") {
		respondError(w, http.StatusUnsupportedMediaType, "content-type must be application/json")
		return false
	}

	// Limit body size
	r.Body = http.MaxBytesReader(w, r.Body, maxRequestBody)

	body, err := io.ReadAll(r.Body)
	if err != nil {
		respondError(w, http.StatusBadRequest, "request body too large or unreadable", err.Error())
		return false
	}

	if err := json.Unmarshal(body, v); err != nil {
		respondError(w, http.StatusBadRequest, "invalid request body", err.Error())
		return false
	}
	return true
}

// validateCameraID checks that cameraID is present and within max length.
func validateCameraID(w http.ResponseWriter, cameraID string) bool {
	if cameraID == "" {
		respondError(w, http.StatusBadRequest, "camera_id is required")
		return false
	}
	if len(cameraID) > maxCameraIDLen {
		respondError(w, http.StatusBadRequest, fmt.Sprintf("camera_id must be at most %d characters", maxCameraIDLen))
		return false
	}
	return true
}

// validateCameraRegistration validates fields for POST /cameras.
func validateCameraRegistration(w http.ResponseWriter, cameraID, friendlyName string) bool {
	if !validateCameraID(w, cameraID) {
		return false
	}
	if friendlyName == "" {
		respondError(w, http.StatusBadRequest, "friendly_name is required")
		return false
	}
	if len(friendlyName) > maxFriendlyNameLen {
		respondError(w, http.StatusBadRequest, fmt.Sprintf("friendly_name must be at most %d characters", maxFriendlyNameLen))
		return false
	}
	return true
}

// validateStatusFields validates optional fields on the PushStatus payload.
func validateStatusFields(w http.ResponseWriter, mode, resolution string, fps int) bool {
	if mode != "" && len(mode) > maxModeLen {
		respondError(w, http.StatusBadRequest, fmt.Sprintf("mode must be at most %d characters", maxModeLen))
		return false
	}
	if resolution != "" && len(resolution) > maxResolutionLen {
		respondError(w, http.StatusBadRequest, fmt.Sprintf("resolution must be at most %d characters", maxResolutionLen))
		return false
	}
	if fps < minFPS || fps > maxFPS {
		respondError(w, http.StatusBadRequest, fmt.Sprintf("fps must be between %d and %d", minFPS, maxFPS))
		return false
	}
	return true
}
