package github

import (
	"context"
	"fmt"
	"reflect"

	"github.com/tidbcloud/AgentTeam/internal/extension/registry"
	"github.com/tidbcloud/AgentTeam/internal/service/prwatch"
)

// Executor is GitHub's real in-process Builtin executor.
type Executor struct {
	service prwatch.Invoker
}

// NewExecutor binds the GitHub provider identity to the shared watch service.
func NewExecutor(service prwatch.Invoker) *Executor {
	return &Executor{service: service}
}

// Strategy identifies this as an in-process native executor.
func (*Executor) Strategy() string {
	return "native"
}

// Invoke adapts the registry Builtin contract to the provider-neutral watch
// service.
func (executor *Executor) Invoke(
	ctx context.Context,
	invocation registry.BuiltinInvocation,
) (registry.BuiltinResult, error) {
	if executor == nil || isNilInvoker(executor.service) {
		return registry.BuiltinResult{}, fmt.Errorf("github pull request watch executor is not configured")
	}
	data, err := executor.service.Invoke(ctx, prwatch.Invocation{
		Provider:              Provider,
		WorkspaceID:           invocation.WorkspaceID,
		AgentID:               invocation.AgentID,
		AgentMemberID:         invocation.AgentMemberID,
		ServiceInstallationID: invocation.ServiceInstallationID,
		Action:                invocation.Action,
		Input:                 append([]byte(nil), invocation.Input...),
	})
	if err != nil {
		return registry.BuiltinResult{}, prwatch.ClassifyInvocationError(err)
	}
	return registry.BuiltinResult{Data: append([]byte(nil), data...)}, nil
}

// Register registers GitHub's independently owned Definition and real executor.
func Register(
	extensionRegistry *registry.Registry,
	service prwatch.Invoker,
) error {
	if extensionRegistry == nil {
		return fmt.Errorf("github extension registry is required")
	}
	if isNilInvoker(service) {
		return fmt.Errorf("github pull request watch service is required")
	}
	if _, err := extensionRegistry.RegisterBuiltin(
		Definition(),
		NewExecutor(service),
		Revision,
	); err != nil {
		return fmt.Errorf("register github Builtin: %w", err)
	}
	return nil
}

func isNilInvoker(invoker prwatch.Invoker) bool {
	if invoker == nil {
		return true
	}
	value := reflect.ValueOf(invoker)
	switch value.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map,
		reflect.Pointer, reflect.Slice:
		return value.IsNil()
	default:
		return false
	}
}
