package quotation

import (
	"context"
	"strings"

	"github.com/tech/sendico/pkg/merrors"
	ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1"
	"go.uber.org/zap"
)

type ledgerAccountCurrencyResolver struct {
	client ledgerClientForCurrency
	logger *zap.Logger
}

type ledgerClientForCurrency interface {
	GetBalance(ctx context.Context, req *ledgerv1.GetBalanceRequest) (*ledgerv1.BalanceResponse, error)
	ListAccounts(ctx context.Context, req *ledgerv1.ListAccountsRequest) (*ledgerv1.ListAccountsResponse, error)
}

func newLedgerAccountCurrencyResolver(core *Service) *ledgerAccountCurrencyResolver {
	if core == nil || core.deps.ledger == nil {
		return nil
	}
	logger := core.logger
	if logger == nil {
		logger = zap.NewNop()
	}
	return &ledgerAccountCurrencyResolver{
		client: core.deps.ledger,
		logger: logger,
	}
}

func (r *ledgerAccountCurrencyResolver) ResolveLedgerAccountCurrency(
	ctx context.Context,
	organizationRef string,
	ledgerAccountRef string,
) (string, error) {
	if r == nil || r.client == nil {
		return "", merrors.NoData("ledger client unavailable")
	}

	accountRef := strings.TrimSpace(ledgerAccountRef)
	if accountRef == "" {
		return "", merrors.InvalidArgument("ledger_account_ref is required")
	}

	balanceResp, err := r.client.GetBalance(ctx, &ledgerv1.GetBalanceRequest{
		LedgerAccountRef: accountRef,
	})
	if err != nil {
		return "", err
	}
	if balance := balanceResp.GetBalance(); balance != nil {
		if currency := strings.ToUpper(strings.TrimSpace(balance.GetCurrency())); currency != "" {
			return currency, nil
		}
	}

	orgRef := strings.TrimSpace(organizationRef)
	if orgRef == "" {
		return "", merrors.NoData("ledger account currency is missing")
	}

	listResp, err := r.client.ListAccounts(ctx, &ledgerv1.ListAccountsRequest{
		OrganizationRef: orgRef,
	})
	if err != nil {
		return "", err
	}
	for _, account := range listResp.GetAccounts() {
		if strings.TrimSpace(account.GetLedgerAccountRef()) != accountRef {
			continue
		}
		if currency := strings.ToUpper(strings.TrimSpace(account.GetCurrency())); currency != "" {
			return currency, nil
		}
		break
	}

	if r.logger != nil {
		r.logger.Warn("Failed to resolve ledger account currency",
			zap.String("organization_ref", orgRef),
			zap.String("ledger_account_ref", accountRef),
		)
	}
	return "", merrors.NoData("ledger account currency is missing")
}
