package protocol

import (
	"fmt"
	"net"

	json "github.com/goccy/go-json"
	"go.uber.org/zap"
)

// ErrorSender handles sending error frames over connections.
type ErrorSender struct {
	conn        net.Conn
	frameWriter *FrameWriter
	logger      *zap.Logger
}

// NewErrorSender creates a new error sender.
func NewErrorSender(conn net.Conn, frameWriter *FrameWriter, logger *zap.Logger) *ErrorSender {
	return &ErrorSender{
		conn:        conn,
		frameWriter: frameWriter,
		logger:      logger,
	}
}

// SendError sends an error frame with the given code and message.
func (e *ErrorSender) SendError(code, message string) error {
	errMsg := ErrorMessage{
		Code:    code,
		Message: message,
	}

	data, err := json.Marshal(errMsg)
	if err != nil {
		e.logger.Error("Failed to marshal error message", zap.Error(err))
		return fmt.Errorf("failed to marshal error: %w", err)
	}

	errFrame := NewFrame(FrameTypeError, data)

	if e.frameWriter == nil {
		return WriteFrame(e.conn, errFrame)
	}

	return e.frameWriter.WriteFrame(errFrame)
}

// SendAuthenticationError sends an authentication failed error.
func (e *ErrorSender) SendAuthenticationError() error {
	return e.SendError("authentication_failed", "Invalid authentication token")
}

// SendRegistrationError sends a registration failed error.
func (e *ErrorSender) SendRegistrationError(message string) error {
	return e.SendError("registration_failed", message)
}

// SendPortAllocationError sends a port allocation failed error.
func (e *ErrorSender) SendPortAllocationError(message string) error {
	return e.SendError("port_allocation_failed", message)
}

// SendTunnelTypeNotAllowedError sends a tunnel type not allowed error.
func (e *ErrorSender) SendTunnelTypeNotAllowedError(tunnelType string) error {
	return e.SendError("tunnel_type_not_allowed",
		fmt.Sprintf("Tunnel type '%s' is not allowed on this server", tunnelType))
}
