package entity

import (
	"fmt"
	"time"

	"github.com/genex/translate-service/internal/domain/vo"
)

// AddressMapping is the aggregate root that maps an internal platform address
// to an on-chain address for a given blockchain network.
type AddressMapping struct {
	ID              string    `json:"id"`
	UserID          string    `json:"userId"`
	InternalAddress string    `json:"internalAddress"`
	ChainAddress    string    `json:"chainAddress"`
	ChainType       string    `json:"chainType"`
	IsActive        bool      `json:"isActive"`
	CreatedAt       time.Time `json:"createdAt"`
	UpdatedAt       time.Time `json:"updatedAt"`
}

// NewAddressMapping is the factory method that creates a fully validated AddressMapping.
// It enforces all domain invariants at creation time.
func NewAddressMapping(id, userID, internalAddr, chainAddr, chainType string) (*AddressMapping, error) {
	if id == "" {
		return nil, fmt.Errorf("mapping ID must not be empty")
	}
	if userID == "" {
		return nil, fmt.Errorf("user ID must not be empty")
	}

	// Validate internal address via value object
	if _, err := vo.NewAddress(internalAddr); err != nil {
		return nil, fmt.Errorf("invalid internal address: %w", err)
	}

	// Validate chain address via value object
	if _, err := vo.NewAddress(chainAddr); err != nil {
		return nil, fmt.Errorf("invalid chain address: %w", err)
	}

	// Validate chain type via value object
	if _, err := vo.NewChainType(chainType); err != nil {
		return nil, err
	}

	now := time.Now()
	return &AddressMapping{
		ID:              id,
		UserID:          userID,
		InternalAddress: internalAddr,
		ChainAddress:    chainAddr,
		ChainType:       chainType,
		IsActive:        true,
		CreatedAt:       now,
		UpdatedAt:       now,
	}, nil
}

// Validate checks all domain invariants on an existing mapping.
func (m *AddressMapping) Validate() error {
	if m.ID == "" {
		return fmt.Errorf("mapping ID must not be empty")
	}
	if m.UserID == "" {
		return fmt.Errorf("user ID must not be empty")
	}
	if _, err := vo.NewAddress(m.InternalAddress); err != nil {
		return fmt.Errorf("invalid internal address: %w", err)
	}
	if _, err := vo.NewAddress(m.ChainAddress); err != nil {
		return fmt.Errorf("invalid chain address: %w", err)
	}
	if _, err := vo.NewChainType(m.ChainType); err != nil {
		return err
	}
	return nil
}

// Deactivate marks the mapping as inactive.
func (m *AddressMapping) Deactivate() {
	m.IsActive = false
	m.UpdatedAt = time.Now()
}

// Activate marks the mapping as active.
func (m *AddressMapping) Activate() {
	m.IsActive = true
	m.UpdatedAt = time.Now()
}

// BelongsToUser checks whether this mapping belongs to the specified user.
func (m *AddressMapping) BelongsToUser(userID string) bool {
	return m.UserID == userID
}
