package certacme

import (
	"context"
	"errors"
	"fmt"

	"github.com/go-acme/lego/v5/lego"

	"github.com/certimate-go/certimate/internal/app"
)

type ACMEClient struct {
	client  *lego.Client
	account *ACMEAccount
}

// Deprecated: use [NewACMEClientWithAccount] instead.
func NewACMEClient(config *ACMEConfig, email string, configures ...func(*lego.Config) error) (*ACMEClient, error) {
	account, err := CreateACMEAccountWithSingleFlight(context.Background(), config, email)
	if err != nil {
		return nil, err
	}

	mergedConfigures := []func(*lego.Config) error{
		func(legoCfg *lego.Config) error {
			legoCfg.CADirURL = config.CADirUrl
			return nil
		},
	}
	mergedConfigures = append(mergedConfigures, configures...)
	return newACMEClientWithAccount(account, mergedConfigures...)
}

func NewACMEClientWithAccount(account *ACMEAccount, configures ...func(*lego.Config) error) (*ACMEClient, error) {
	return newACMEClientWithAccount(account, configures...)
}

func newACMEClientWithAccount(account *ACMEAccount, configures ...func(*lego.Config) error) (*ACMEClient, error) {
	if account == nil {
		return nil, fmt.Errorf("the acme account is nil")
	}

	legoCfg := lego.NewConfig(account)
	legoCfg.UserAgent = app.AppUserAgent
	legoCfg.CADirURL = account.ACMEDirectoryUrl

	errs := make([]error, 0)
	for _, configure := range configures {
		if err := configure(legoCfg); err != nil {
			errs = append(errs, err)
		}
	}

	if len(errs) > 0 {
		return nil, errors.Join(errs...)
	}

	legoClient, err := lego.NewClient(legoCfg)
	if err != nil {
		return nil, err
	}

	return &ACMEClient{
		client:  legoClient,
		account: account,
	}, nil
}
