package sresponse

import (
	"net/http"
	"time"

	"github.com/tech/sendico/pkg/api/http/response"
	"github.com/tech/sendico/pkg/mlogger"
	moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
	ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1"
)

type ledgerAccount struct {
	LedgerAccountRef string            `json:"ledgerAccountRef"`
	OrganizationRef  string            `json:"organizationRef"`
	AccountCode      string            `json:"accountCode"`
	AccountType      string            `json:"accountType"`
	Currency         string            `json:"currency"`
	Status           string            `json:"status"`
	AllowNegative    bool              `json:"allowNegative"`
	IsSettlement     bool              `json:"isSettlement"`
	Metadata         map[string]string `json:"metadata,omitempty"`
	CreatedAt        time.Time         `json:"createdAt,omitempty"`
	UpdatedAt        time.Time         `json:"updatedAt,omitempty"`
}

type ledgerAccountsResponse struct {
	authResponse `json:",inline"`
	Accounts     []ledgerAccount `json:"accounts"`
}

type ledgerMoney struct {
	Amount   string `json:"amount"`
	Currency string `json:"currency"`
}

type ledgerBalance struct {
	LedgerAccountRef string       `json:"ledgerAccountRef"`
	Balance          *ledgerMoney `json:"balance,omitempty"`
	Version          int64        `json:"version"`
	LastUpdated      time.Time    `json:"lastUpdated,omitempty"`
}

type ledgerBalanceResponse struct {
	authResponse `json:",inline"`
	Balance      ledgerBalance `json:"balance"`
}

func LedgerAccounts(logger mlogger.Logger, accounts []*ledgerv1.LedgerAccount, accessToken *TokenData) http.HandlerFunc {
	dto := make([]ledgerAccount, 0, len(accounts))
	for _, acc := range accounts {
		dto = append(dto, toLedgerAccount(acc))
	}
	return response.Ok(logger, ledgerAccountsResponse{
		Accounts:     dto,
		authResponse: authResponse{AccessToken: *accessToken},
	})
}

func LedgerBalance(logger mlogger.Logger, resp *ledgerv1.BalanceResponse, accessToken *TokenData) http.HandlerFunc {
	return response.Ok(logger, ledgerBalanceResponse{
		Balance:      toLedgerBalance(resp),
		authResponse: authResponse{AccessToken: *accessToken},
	})
}

func toLedgerAccount(acc *ledgerv1.LedgerAccount) ledgerAccount {
	if acc == nil {
		return ledgerAccount{}
	}
	return ledgerAccount{
		LedgerAccountRef: acc.GetLedgerAccountRef(),
		OrganizationRef:  acc.GetOrganizationRef(),
		AccountCode:      acc.GetAccountCode(),
		AccountType:      acc.GetAccountType().String(),
		Currency:         acc.GetCurrency(),
		Status:           acc.GetStatus().String(),
		AllowNegative:    acc.GetAllowNegative(),
		IsSettlement:     acc.GetIsSettlement(),
		Metadata:         acc.GetMetadata(),
		CreatedAt:        acc.GetCreatedAt().AsTime(),
		UpdatedAt:        acc.GetUpdatedAt().AsTime(),
	}
}

func toLedgerBalance(resp *ledgerv1.BalanceResponse) ledgerBalance {
	if resp == nil {
		return ledgerBalance{}
	}
	return ledgerBalance{
		LedgerAccountRef: resp.GetLedgerAccountRef(),
		Balance:          toLedgerMoney(resp.GetBalance()),
		Version:          resp.GetVersion(),
		LastUpdated:      resp.GetLastUpdated().AsTime(),
	}
}

func toLedgerMoney(m *moneyv1.Money) *ledgerMoney {
	if m == nil {
		return nil
	}
	return &ledgerMoney{
		Amount:   m.GetAmount(),
		Currency: m.GetCurrency(),
	}
}
