package agent

import (
	"context"
	"log/slog"
	"time"

	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/module/agent_registrar"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/grpctool"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/logz"
	"gitlab.com/gitlab-org/cluster-integration/tunnel/tool/retry"
)

type Module[CM any] struct {
	Log        *slog.Logger
	PollConfig retry.PollConfig

	Register   func(ctx context.Context) error
	Unregister func(ctx context.Context) error
}

func (m *Module[CM]) Run(ctx context.Context, cfg <-chan CM) error {
	// Defer unregistration of this agent on shut down.
	defer func() {
		unregisterCtx, unregisterCancel := context.WithTimeout(context.WithoutCancel(ctx), 1*time.Second)
		defer unregisterCancel()
		err := m.Unregister(unregisterCtx)
		if err != nil {
			m.Log.Error("Unable to unregister", logz.Error(err))
		}
	}()

	_ = retry.PollWithBackoff(ctx, m.PollConfig, func(ctx context.Context) (error, retry.AttemptResult) { //nolint:staticcheck
		err := m.Register(ctx)
		if err != nil {
			if !grpctool.RequestCanceledOrTimedOut(err) {
				m.Log.Error("Failed to register agent instance. Please make sure the agent version matches the server version", logz.Error(err))
			}
			return nil, retry.Backoff
		}

		return nil, retry.Continue
	})
	return nil
}

func (m *Module[CM]) DefaultAndValidateConfiguration(config CM) error {
	return nil
}

func (m *Module[CM]) Name() string {
	return agent_registrar.ModuleName
}
