// Package validate provides WebSocket handlers for validation-related operations
package validate

import (
	"errors"
	"net/http"
	"time"

	"github.com/gorilla/websocket"
	"github.com/jfraeys/fetch_ml/internal/api/helpers"
	"github.com/jfraeys/fetch_ml/internal/auth"
	"github.com/jfraeys/fetch_ml/internal/experiment"
	"github.com/jfraeys/fetch_ml/internal/logging"
)

// Handler provides validation-related WebSocket handlers
type Handler struct {
	expManager *experiment.Manager
	logger     *logging.Logger
	authConfig *auth.Config
}

// NewHandler creates a new validate handler
func NewHandler(
	expManager *experiment.Manager,
	logger *logging.Logger,
	authConfig *auth.Config,
) *Handler {
	return &Handler{
		expManager: expManager,
		logger:     logger,
		authConfig: authConfig,
	}
}

// Error codes
const (
	ErrorCodeUnknownError         = 0x00
	ErrorCodeInvalidRequest       = 0x01
	ErrorCodeAuthenticationFailed = 0x02
	ErrorCodePermissionDenied     = 0x03
	ErrorCodeResourceNotFound     = 0x04
	ErrorCodeValidationFailed     = 0x40
)

// Permissions
const (
	PermJobsRead = "jobs:read"
)

// sendErrorPacket sends an error response packet to the client
func (h *Handler) sendErrorPacket(conn *websocket.Conn, code byte, message, details string) error {
	err := map[string]interface{}{
		"error":   true,
		"code":    code,
		"message": message,
		"details": details,
	}
	return conn.WriteJSON(err)
}

// sendSuccessPacket sends a success response packet
func (h *Handler) sendSuccessPacket(conn *websocket.Conn, data map[string]interface{}) error {
	return conn.WriteJSON(data)
}

// ValidateRequest represents a validation request
// Protocol: [api_key_hash:16][validate_id_len:1][validate_id:var][commit_id:20]
type ValidateRequest struct {
	ValidateID string
	CommitID   string
}

// ParseValidateRequest parses a validation request from the payload
func ParseValidateRequest(payload []byte) (*ValidateRequest, error) {
	if len(payload) < 16+1+20 {
		return nil, errors.New("validate request payload too short")
	}

	offset := 16

	validateIDLen := int(payload[offset])
	offset += 1
	if validateIDLen <= 0 || len(payload) < offset+validateIDLen+20 {
		return nil, errors.New("invalid validate id length")
	}
	validateID := string(payload[offset : offset+validateIDLen])
	offset += validateIDLen

	commitID := string(payload[offset : offset+20])

	return &ValidateRequest{
		ValidateID: validateID,
		CommitID:   commitID,
	}, nil
}

// HandleValidate handles the validate WebSocket operation
func (h *Handler) HandleValidate(conn *websocket.Conn, payload []byte, user *auth.User) error {
	req, err := ParseValidateRequest(payload)
	if err != nil {
		return h.sendErrorPacket(conn, ErrorCodeInvalidRequest, "invalid validate request", err.Error())
	}

	h.logger.Info("validation requested", "validate_id", req.ValidateID, "commit_id", req.CommitID, "user", user.Name)

	// Validate commit ID format
	if ok, errMsg := helpers.ValidateCommitIDFormat(req.CommitID); !ok {
		return h.sendErrorPacket(conn, ErrorCodeInvalidRequest, "invalid commit_id format", errMsg)
	}

	// Validate experiment manifest
	if ok, details := helpers.ValidateExperimentManifest(h.expManager, req.CommitID); !ok {
		return h.sendErrorPacket(conn, ErrorCodeResourceNotFound, "experiment manifest validation failed", details)
	}

	// Create validation report
	report := helpers.NewValidateReport()
	report.CommitID = req.CommitID
	report.TS = time.Now().UTC().Format(time.RFC3339)

	// Add basic checks
	report.Checks["commit_id_format"] = helpers.ValidateCheck{OK: true, Expected: "40 hex chars", Actual: req.CommitID}
	report.Checks["manifest_exists"] = helpers.ValidateCheck{OK: true, Expected: "present", Actual: "found"}

	return h.sendSuccessPacket(conn, map[string]interface{}{
		"success":     true,
		"validate_id": req.ValidateID,
		"commit_id":   req.CommitID,
		"report":      report,
		"timestamp":   time.Now().UTC(),
	})
}

// HandleGetValidateStatus handles getting the status of a validation
func (h *Handler) HandleGetValidateStatus(conn *websocket.Conn, validateID string, user *auth.User) error {
	h.logger.Info("getting validation status", "validate_id", validateID, "user", user.Name)

	// Stub implementation - in production, would query validation status from database

	return h.sendSuccessPacket(conn, map[string]interface{}{
		"success":     true,
		"validate_id": validateID,
		"status":      "completed",
		"timestamp":   time.Now().UTC(),
	})
}

// HandleListValidations handles listing all validations for a commit
func (h *Handler) HandleListValidations(conn *websocket.Conn, commitID string, user *auth.User) error {
	h.logger.Info("listing validations", "commit_id", commitID, "user", user.Name)

	// Stub implementation - in production, would query validations from database

	return h.sendSuccessPacket(conn, map[string]interface{}{
		"success":   true,
		"commit_id": commitID,
		"validations": []map[string]interface{}{
			{
				"validate_id": "val-001",
				"status":      "completed",
				"timestamp":   time.Now().UTC(),
			},
		},
		"count": 1,
	})
}

// HTTP Handlers for REST API

// ValidateHTTP handles HTTP requests for validation
func (h *Handler) ValidateHTTP(w http.ResponseWriter, r *http.Request) {
	http.Error(w, "Not implemented", http.StatusNotImplemented)
}

// GetValidationStatusHTTP handles HTTP requests for validation status
func (h *Handler) GetValidationStatusHTTP(w http.ResponseWriter, r *http.Request) {
	http.Error(w, "Not implemented", http.StatusNotImplemented)
}
