// Package todoist registers the Todoist Builtin Extension ported from
// OpenConnector (baseline 0484cac): REST v1 over Bearer token auth with
// cursor pagination. Outputs are bounded provider passthrough objects.
package todoist

import (
	"context"
	"fmt"

	"github.com/tidbcloud/AgentTeam/internal/extension"
	"github.com/tidbcloud/AgentTeam/internal/extension/registry"
	"github.com/tidbcloud/AgentTeam/internal/extension/runner"
)

const (
	// Domain is the Extension domain.
	Domain = "todoist"
	// Revision is the implementation identity folded into the runtime digest.
	Revision = "todoist-rest-v1"
	// BaseURL is the fixed Todoist REST v1 origin.
	BaseURL = "https://api.todoist.com/api/v1"
)

// Extension composes the Todoist Builtin. It fails closed when the credential
// source or provider client cannot be constructed.
func Extension(credentials runner.CredentialSource) (extension.Extension, error) {
	client, err := runner.NewRESTClient(runner.RESTOptions{
		BaseURL: BaseURL,
		Auth:    AuthSpec(),
	})
	if err != nil {
		return extension.Extension{}, fmt.Errorf("todoist: build REST client: %w", err)
	}
	executor := runner.NewRESTExecutor(Domain, client, credentials, Handlers())
	return extension.Extension{
		Definition: Definition(),
		Implementation: runner.Implementation{
			Executor:            executor,
			Revision:            Revision,
			ConnectionPolicy:    registry.ConnectionRequired,
			Auth:                AuthSpec(),
			ValidateCredentials: ValidateCredentials,
		},
		Distribution: extension.Distribution{
			AppID:          "app_todoist",
			AppSlug:        "todoist",
			DefaultName:    Domain,
			DefaultEnabled: true,
			IconURL:        "/app-icons/todoist.svg",
		},
	}, nil
}

// AuthSpec declares the API-token credential contract.
func AuthSpec() runner.AuthSpec {
	return runner.AuthSpec{
		Kind: runner.AuthBearer,
		Fields: []runner.CredentialField{
			runner.APIKeyField(
				"Todoist API token",
				"A Todoist OAuth access token or personal API token, sent as an Authorization Bearer header.",
			),
		},
	}
}

// ValidateCredentials live-checks the token with one bounded /user request.
func ValidateCredentials(ctx context.Context, credentials runner.Credentials) error {
	client, err := runner.NewRESTClient(runner.RESTOptions{
		BaseURL: BaseURL,
		Auth:    AuthSpec(),
	})
	if err != nil {
		return err
	}
	var profile struct {
		ID string `json:"id"`
	}
	if err := client.CallJSON(ctx, credentials, runner.RESTRequest{
		Method: "GET",
		Path:   "/user",
	}, &profile); err != nil {
		return err
	}
	if profile.ID == "" {
		return runner.Errorf(
			runner.ErrorProviderAuthUnavailable, "todoist rejected the token", nil)
	}
	return nil
}
