package contrib

import (
	"fmt"

	"github.com/keepmind9/acp-sdk-go/schema"
)

func ptrOptId(s string) *schema.PermissionOptionId                                  { v := schema.PermissionOptionId(s); return &v }
func ptrKind(k schema.PermissionOptionKind) *schema.PermissionOptionKind            { return &k }
func ptrOutcome(o schema.RequestPermissionOutcome) *schema.RequestPermissionOutcome { return &o }

// PermissionRequester is a function that sends a permission request and returns the response.
type PermissionRequester func(req *schema.RequestPermissionRequest) (*schema.RequestPermissionResponse, error)

// PermissionBroker helps issue permission requests tied to tracked tool calls.
type PermissionBroker struct {
	sessionID      string
	requester      PermissionRequester
	tracker        *ToolCallTracker
	defaultOptions []*schema.PermissionOption
}

// NewPermissionBroker creates a new PermissionBroker.
func NewPermissionBroker(sessionID string, requester PermissionRequester, opts ...PermissionBrokerOption) *PermissionBroker {
	pb := &PermissionBroker{
		sessionID: sessionID,
		requester: requester,
		defaultOptions: []*schema.PermissionOption{
			{OptionId: ptrOptId("approve"), Name: "Approve", Kind: ptrKind(schema.PermissionOptionKindAllowOnce)},
			{OptionId: ptrOptId("approve_for_session"), Name: "Approve for session", Kind: ptrKind(schema.PermissionOptionKindAllowAlways)},
			{OptionId: ptrOptId("reject"), Name: "Reject", Kind: ptrKind(schema.PermissionOptionKindRejectOnce)},
		},
	}
	for _, opt := range opts {
		opt(pb)
	}
	return pb
}

// PermissionBrokerOption configures a PermissionBroker.
type PermissionBrokerOption func(*PermissionBroker)

// WithTracker sets the tool call tracker.
func WithTracker(tracker *ToolCallTracker) PermissionBrokerOption {
	return func(pb *PermissionBroker) { pb.tracker = tracker }
}

// WithDefaultOptions sets the default permission options.
func WithDefaultOptions(options []*schema.PermissionOption) PermissionBrokerOption {
	return func(pb *PermissionBroker) {
		if len(options) > 0 {
			pb.defaultOptions = make([]*schema.PermissionOption, len(options))
			copy(pb.defaultOptions, options)
		}
	}
}

// RequestFor requests user approval for a tool call.
// If toolCall is nil and a tracker is configured, it uses the tracked tool call.
func (pb *PermissionBroker) RequestFor(externalID string, opts ...PermissionRequestOption) (*schema.RequestPermissionResponse, error) {
	cfg := &permissionRequestConfig{
		options: pb.defaultOptions,
	}
	for _, opt := range opts {
		opt(cfg)
	}

	if len(cfg.options) == 0 {
		return nil, fmt.Errorf("at least one permission option is required")
	}

	var toolCallUpdate schema.ToolCallUpdate
	if cfg.toolCall != nil {
		toolCallUpdate = *cfg.toolCall
	} else if pb.tracker != nil {
		var err error
		toolCallUpdate, err = pb.tracker.ToolCallUpdate(externalID)
		if err != nil {
			return nil, fmt.Errorf("getting tool call: %w", err)
		}
	} else {
		return nil, fmt.Errorf("tool_call must be provided when no ToolCallTracker is configured")
	}

	if cfg.content != nil {
		toolCallUpdate.Content = cfg.content
	}

	sessionID := schema.SessionId(pb.sessionID)
	req := &schema.RequestPermissionRequest{
		SessionId: &sessionID,
		Options:   cfg.options,
		ToolCall:  &toolCallUpdate,
	}

	return pb.requester(req)
}

type permissionRequestConfig struct {
	toolCall *schema.ToolCallUpdate
	content  []*schema.ToolCallContent
	options  []*schema.PermissionOption
}

// PermissionRequestOption configures a permission request.
type PermissionRequestOption func(*permissionRequestConfig)

// WithToolCall sets the tool call for the permission request.
func WithToolCall(tc schema.ToolCallUpdate) PermissionRequestOption {
	return func(cfg *permissionRequestConfig) { cfg.toolCall = &tc }
}

// WithPermissionContent sets the content for the permission request.
func WithPermissionContent(content []*schema.ToolCallContent) PermissionRequestOption {
	return func(cfg *permissionRequestConfig) { cfg.content = content }
}

// WithPermissionOptions sets the permission options.
func WithPermissionOptions(options []*schema.PermissionOption) PermissionRequestOption {
	return func(cfg *permissionRequestConfig) { cfg.options = options }
}
