package account

import (
	"context"

	"github.com/jackc/pgx/v5/pgtype"

	"github.com/TaruLab/keluargamart-backend/internal/db"
)

type Service struct {
	repo *Repository
}

func NewService(repo *Repository) *Service {
	return &Service{repo: repo}
}

// List returns the buyer's address book.
func (s *Service) List(ctx context.Context, userID int64) ([]Address, error) {
	rows, err := s.repo.List(ctx, userID)
	if err != nil {
		return nil, err
	}
	out := make([]Address, 0, len(rows))
	for _, row := range rows {
		out = append(out, toAddress(row))
	}
	return out, nil
}

// Create validates and stores a new address for the buyer.
func (s *Service) Create(ctx context.Context, userID int64, in AddressInput) (Address, error) {
	if msg, ok := in.validate(); !ok {
		return Address{}, newInvalid(msg)
	}
	row, err := s.repo.Create(ctx, userID, in)
	if err != nil {
		return Address{}, err
	}
	return toAddress(row), nil
}

// Update validates and replaces an existing address owned by the buyer.
func (s *Service) Update(ctx context.Context, userID, id int64, in AddressInput) (Address, error) {
	if msg, ok := in.validate(); !ok {
		return Address{}, newInvalid(msg)
	}
	row, err := s.repo.Update(ctx, userID, id, in)
	if err != nil {
		return Address{}, err
	}
	return toAddress(row), nil
}

// Delete removes an address owned by the buyer.
func (s *Service) Delete(ctx context.Context, userID, id int64) error {
	return s.repo.Delete(ctx, userID, id)
}

// toAddress converts the sqlc row (pgtype optionals) into the JSON model.
func toAddress(row db.BuyerAddress) Address {
	return Address{
		ID:                row.ID,
		Label:             row.Label,
		ContactName:       row.ContactName,
		Phone:             row.Phone,
		Line1:             row.Line1,
		Line2:             textPtr(row.Line2),
		City:              row.City,
		Province:          textPtr(row.Province),
		PostalCode:        row.PostalCode,
		Country:           row.Country,
		Latitude:          floatPtr(row.Latitude),
		Longitude:         floatPtr(row.Longitude),
		IsDefaultShipping: row.IsDefaultShipping,
		IsDefaultBilling:  row.IsDefaultBilling,
	}
}

func textPtr(t pgtype.Text) *string {
	if !t.Valid {
		return nil
	}
	v := t.String
	return &v
}

func floatPtr(f pgtype.Float8) *float64 {
	if !f.Valid {
		return nil
	}
	v := f.Float64
	return &v
}

func pgText(s *string) pgtype.Text {
	if s == nil {
		return pgtype.Text{}
	}
	return pgtype.Text{String: *s, Valid: true}
}

func pgFloat(f *float64) pgtype.Float8 {
	if f == nil {
		return pgtype.Float8{}
	}
	return pgtype.Float8{Float64: *f, Valid: true}
}

func orDefault(s, fallback string) string {
	if s == "" {
		return fallback
	}
	return s
}
