package state

import (
	"errors"
	"fmt"
	"math/big"

	"git.marketally.com/tutus-one/tutus-chain/pkg/util"
	"git.marketally.com/tutus-one/tutus-chain/pkg/vm/stackitem"
)

// LifePlanAccountStatus represents the status of a life planning account.
type LifePlanAccountStatus uint8

const (
	// LifePlanAccountActive indicates an active account.
	LifePlanAccountActive LifePlanAccountStatus = 0
	// LifePlanAccountSuspended indicates a suspended account.
	LifePlanAccountSuspended LifePlanAccountStatus = 1
	// LifePlanAccountClosed indicates a closed account.
	LifePlanAccountClosed LifePlanAccountStatus = 2
)

// CareerCycleStatus represents the status of a career cycle.
type CareerCycleStatus uint8

const (
	// CareerCycleActive indicates an active career.
	CareerCycleActive CareerCycleStatus = 0
	// CareerCycleCompleted indicates a completed career.
	CareerCycleCompleted CareerCycleStatus = 1
	// CareerCycleTransitioning indicates transitioning to new career.
	CareerCycleTransitioning CareerCycleStatus = 2
)

// SabbaticalStatus represents the status of a sabbatical.
type SabbaticalStatus uint8

const (
	// SabbaticalPlanned indicates a planned sabbatical.
	SabbaticalPlanned SabbaticalStatus = 0
	// SabbaticalActive indicates an active sabbatical.
	SabbaticalActive SabbaticalStatus = 1
	// SabbaticalCompleted indicates a completed sabbatical.
	SabbaticalCompleted SabbaticalStatus = 2
	// SabbaticalCancelled indicates a cancelled sabbatical.
	SabbaticalCancelled SabbaticalStatus = 3
)

// SabbaticalPurpose represents the purpose of a sabbatical.
type SabbaticalPurpose uint8

const (
	// SabbaticalPurposeEducation for education and learning.
	SabbaticalPurposeEducation SabbaticalPurpose = 0
	// SabbaticalPurposeHealth for health and recovery.
	SabbaticalPurposeHealth SabbaticalPurpose = 1
	// SabbaticalPurposeFamily for family care.
	SabbaticalPurposeFamily SabbaticalPurpose = 2
	// SabbaticalPurposeExploration for personal exploration.
	SabbaticalPurposeExploration SabbaticalPurpose = 3
	// SabbaticalPurposeTransition for career transition.
	SabbaticalPurposeTransition SabbaticalPurpose = 4
	// SabbaticalPurposeVolunteer for volunteering.
	SabbaticalPurposeVolunteer SabbaticalPurpose = 5
)

// MilestoneType represents the type of life milestone.
type MilestoneType uint8

const (
	// MilestoneCareerStart for starting a career.
	MilestoneCareerStart MilestoneType = 0
	// MilestoneCareerEnd for ending a career.
	MilestoneCareerEnd MilestoneType = 1
	// MilestoneEducation for educational achievements.
	MilestoneEducation MilestoneType = 2
	// MilestoneFamily for family events.
	MilestoneFamily MilestoneType = 3
	// MilestoneHealth for health milestones.
	MilestoneHealth MilestoneType = 4
	// MilestoneFinancial for financial goals.
	MilestoneFinancial MilestoneType = 5
	// MilestonePersonal for personal achievements.
	MilestonePersonal MilestoneType = 6
)

// GoalStatus represents the status of a life goal.
type GoalStatus uint8

const (
	// GoalStatusPlanned indicates a planned goal.
	GoalStatusPlanned GoalStatus = 0
	// GoalStatusInProgress indicates an in-progress goal.
	GoalStatusInProgress GoalStatus = 1
	// GoalStatusCompleted indicates a completed goal.
	GoalStatusCompleted GoalStatus = 2
	// GoalStatusAbandoned indicates an abandoned goal.
	GoalStatusAbandoned GoalStatus = 3
)

// LifePlanAccount represents a citizen's life planning account.
type LifePlanAccount struct {
	VitaID                   uint64                // Owner's Vita token ID
	Owner                    util.Uint160          // Owner's address
	TotalContributions       uint64                // Lifetime contributions
	EmployerContributions    uint64                // Employer contributions
	GovernmentContributions  uint64                // Government matching
	CurrentBalance           uint64                // Current account balance
	SabbaticalCredits        uint64                // Available sabbatical credits
	LongevityMultiplier      uint32                // Age-based benefit multiplier (basis points)
	CurrentCareerCycleID     uint64                // Active career cycle ID
	TotalCareerCycles        uint32                // Number of career cycles
	TotalSabbaticals         uint32                // Number of sabbaticals taken
	Status                   LifePlanAccountStatus // Account status
	CreatedAt                uint32                // Block height when created
	UpdatedAt                uint32                // Block height of last update
}

// ToStackItem implements stackitem.Convertible interface.
func (a *LifePlanAccount) ToStackItem() (stackitem.Item, error) {
	return stackitem.NewStruct([]stackitem.Item{
		stackitem.NewBigInteger(big.NewInt(int64(a.VitaID))),
		stackitem.NewByteArray(a.Owner.BytesBE()),
		stackitem.NewBigInteger(big.NewInt(int64(a.TotalContributions))),
		stackitem.NewBigInteger(big.NewInt(int64(a.EmployerContributions))),
		stackitem.NewBigInteger(big.NewInt(int64(a.GovernmentContributions))),
		stackitem.NewBigInteger(big.NewInt(int64(a.CurrentBalance))),
		stackitem.NewBigInteger(big.NewInt(int64(a.SabbaticalCredits))),
		stackitem.NewBigInteger(big.NewInt(int64(a.LongevityMultiplier))),
		stackitem.NewBigInteger(big.NewInt(int64(a.CurrentCareerCycleID))),
		stackitem.NewBigInteger(big.NewInt(int64(a.TotalCareerCycles))),
		stackitem.NewBigInteger(big.NewInt(int64(a.TotalSabbaticals))),
		stackitem.NewBigInteger(big.NewInt(int64(a.Status))),
		stackitem.NewBigInteger(big.NewInt(int64(a.CreatedAt))),
		stackitem.NewBigInteger(big.NewInt(int64(a.UpdatedAt))),
	}), nil
}

// FromStackItem implements stackitem.Convertible interface.
func (a *LifePlanAccount) FromStackItem(item stackitem.Item) error {
	items, ok := item.Value().([]stackitem.Item)
	if !ok {
		return errors.New("not a struct")
	}
	if len(items) != 14 {
		return fmt.Errorf("wrong number of elements: expected 14, got %d", len(items))
	}

	vitaID, err := items[0].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid vitaID: %w", err)
	}
	a.VitaID = vitaID.Uint64()

	owner, err := items[1].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid owner: %w", err)
	}
	a.Owner, err = util.Uint160DecodeBytesBE(owner)
	if err != nil {
		return fmt.Errorf("invalid owner address: %w", err)
	}

	totalContributions, err := items[2].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid totalContributions: %w", err)
	}
	a.TotalContributions = totalContributions.Uint64()

	employerContributions, err := items[3].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid employerContributions: %w", err)
	}
	a.EmployerContributions = employerContributions.Uint64()

	governmentContributions, err := items[4].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid governmentContributions: %w", err)
	}
	a.GovernmentContributions = governmentContributions.Uint64()

	currentBalance, err := items[5].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid currentBalance: %w", err)
	}
	a.CurrentBalance = currentBalance.Uint64()

	sabbaticalCredits, err := items[6].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid sabbaticalCredits: %w", err)
	}
	a.SabbaticalCredits = sabbaticalCredits.Uint64()

	longevityMultiplier, err := items[7].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid longevityMultiplier: %w", err)
	}
	a.LongevityMultiplier = uint32(longevityMultiplier.Uint64())

	currentCareerCycleID, err := items[8].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid currentCareerCycleID: %w", err)
	}
	a.CurrentCareerCycleID = currentCareerCycleID.Uint64()

	totalCareerCycles, err := items[9].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid totalCareerCycles: %w", err)
	}
	a.TotalCareerCycles = uint32(totalCareerCycles.Uint64())

	totalSabbaticals, err := items[10].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid totalSabbaticals: %w", err)
	}
	a.TotalSabbaticals = uint32(totalSabbaticals.Uint64())

	status, err := items[11].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid status: %w", err)
	}
	a.Status = LifePlanAccountStatus(status.Uint64())

	createdAt, err := items[12].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid createdAt: %w", err)
	}
	a.CreatedAt = uint32(createdAt.Uint64())

	updatedAt, err := items[13].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid updatedAt: %w", err)
	}
	a.UpdatedAt = uint32(updatedAt.Uint64())

	return nil
}

// CareerCycle represents a career phase in a person's life.
type CareerCycle struct {
	ID                  uint64            // Unique career cycle ID
	VitaID              uint64            // Owner's Vita ID
	Owner               util.Uint160      // Owner's address
	CareerField         string            // Industry/profession
	StartedAt           uint32            // Block height when started
	EndedAt             uint32            // Block height when ended (0 = active)
	ContributionTotal   uint64            // Total contributions in this cycle
	TransitionReason    string            // Why career ended
	Status              CareerCycleStatus // Career status
}

// ToStackItem implements stackitem.Convertible interface.
func (c *CareerCycle) ToStackItem() (stackitem.Item, error) {
	return stackitem.NewStruct([]stackitem.Item{
		stackitem.NewBigInteger(big.NewInt(int64(c.ID))),
		stackitem.NewBigInteger(big.NewInt(int64(c.VitaID))),
		stackitem.NewByteArray(c.Owner.BytesBE()),
		stackitem.NewByteArray([]byte(c.CareerField)),
		stackitem.NewBigInteger(big.NewInt(int64(c.StartedAt))),
		stackitem.NewBigInteger(big.NewInt(int64(c.EndedAt))),
		stackitem.NewBigInteger(big.NewInt(int64(c.ContributionTotal))),
		stackitem.NewByteArray([]byte(c.TransitionReason)),
		stackitem.NewBigInteger(big.NewInt(int64(c.Status))),
	}), nil
}

// FromStackItem implements stackitem.Convertible interface.
func (c *CareerCycle) FromStackItem(item stackitem.Item) error {
	items, ok := item.Value().([]stackitem.Item)
	if !ok {
		return errors.New("not a struct")
	}
	if len(items) != 9 {
		return fmt.Errorf("wrong number of elements: expected 9, got %d", len(items))
	}

	id, err := items[0].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid id: %w", err)
	}
	c.ID = id.Uint64()

	vitaID, err := items[1].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid vitaID: %w", err)
	}
	c.VitaID = vitaID.Uint64()

	owner, err := items[2].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid owner: %w", err)
	}
	c.Owner, err = util.Uint160DecodeBytesBE(owner)
	if err != nil {
		return fmt.Errorf("invalid owner address: %w", err)
	}

	careerField, err := items[3].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid careerField: %w", err)
	}
	c.CareerField = string(careerField)

	startedAt, err := items[4].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid startedAt: %w", err)
	}
	c.StartedAt = uint32(startedAt.Uint64())

	endedAt, err := items[5].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid endedAt: %w", err)
	}
	c.EndedAt = uint32(endedAt.Uint64())

	contributionTotal, err := items[6].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid contributionTotal: %w", err)
	}
	c.ContributionTotal = contributionTotal.Uint64()

	transitionReason, err := items[7].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid transitionReason: %w", err)
	}
	c.TransitionReason = string(transitionReason)

	status, err := items[8].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid status: %w", err)
	}
	c.Status = CareerCycleStatus(status.Uint64())

	return nil
}

// Sabbatical represents a career break.
type Sabbatical struct {
	ID           uint64            // Unique sabbatical ID
	VitaID       uint64            // Owner's Vita ID
	Owner        util.Uint160      // Owner's address
	Purpose      SabbaticalPurpose // Purpose of sabbatical
	Description  string            // Description of plans
	StartedAt    uint32            // Block height when started
	Duration     uint32            // Planned duration in blocks
	EndedAt      uint32            // Block height when ended (0 = ongoing)
	FundingUsed  uint64            // Credits spent during sabbatical
	Outcome      string            // Sabbatical results
	Status       SabbaticalStatus  // Sabbatical status
}

// ToStackItem implements stackitem.Convertible interface.
func (s *Sabbatical) ToStackItem() (stackitem.Item, error) {
	return stackitem.NewStruct([]stackitem.Item{
		stackitem.NewBigInteger(big.NewInt(int64(s.ID))),
		stackitem.NewBigInteger(big.NewInt(int64(s.VitaID))),
		stackitem.NewByteArray(s.Owner.BytesBE()),
		stackitem.NewBigInteger(big.NewInt(int64(s.Purpose))),
		stackitem.NewByteArray([]byte(s.Description)),
		stackitem.NewBigInteger(big.NewInt(int64(s.StartedAt))),
		stackitem.NewBigInteger(big.NewInt(int64(s.Duration))),
		stackitem.NewBigInteger(big.NewInt(int64(s.EndedAt))),
		stackitem.NewBigInteger(big.NewInt(int64(s.FundingUsed))),
		stackitem.NewByteArray([]byte(s.Outcome)),
		stackitem.NewBigInteger(big.NewInt(int64(s.Status))),
	}), nil
}

// FromStackItem implements stackitem.Convertible interface.
func (s *Sabbatical) FromStackItem(item stackitem.Item) error {
	items, ok := item.Value().([]stackitem.Item)
	if !ok {
		return errors.New("not a struct")
	}
	if len(items) != 11 {
		return fmt.Errorf("wrong number of elements: expected 11, got %d", len(items))
	}

	id, err := items[0].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid id: %w", err)
	}
	s.ID = id.Uint64()

	vitaID, err := items[1].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid vitaID: %w", err)
	}
	s.VitaID = vitaID.Uint64()

	owner, err := items[2].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid owner: %w", err)
	}
	s.Owner, err = util.Uint160DecodeBytesBE(owner)
	if err != nil {
		return fmt.Errorf("invalid owner address: %w", err)
	}

	purpose, err := items[3].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid purpose: %w", err)
	}
	s.Purpose = SabbaticalPurpose(purpose.Uint64())

	description, err := items[4].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid description: %w", err)
	}
	s.Description = string(description)

	startedAt, err := items[5].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid startedAt: %w", err)
	}
	s.StartedAt = uint32(startedAt.Uint64())

	duration, err := items[6].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid duration: %w", err)
	}
	s.Duration = uint32(duration.Uint64())

	endedAt, err := items[7].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid endedAt: %w", err)
	}
	s.EndedAt = uint32(endedAt.Uint64())

	fundingUsed, err := items[8].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid fundingUsed: %w", err)
	}
	s.FundingUsed = fundingUsed.Uint64()

	outcome, err := items[9].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid outcome: %w", err)
	}
	s.Outcome = string(outcome)

	status, err := items[10].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid status: %w", err)
	}
	s.Status = SabbaticalStatus(status.Uint64())

	return nil
}

// LifeMilestone represents a significant life event.
type LifeMilestone struct {
	ID            uint64        // Unique milestone ID
	VitaID        uint64        // Owner's Vita ID
	Owner         util.Uint160  // Owner's address
	MilestoneType MilestoneType // Type of milestone
	Title         string        // Milestone title
	Description   string        // Milestone description
	ContentHash   util.Uint256  // Hash of supporting documentation
	AchievedAt    uint32        // Block height when achieved
	IsVerified    bool          // Whether milestone is verified
}

// ToStackItem implements stackitem.Convertible interface.
func (m *LifeMilestone) ToStackItem() (stackitem.Item, error) {
	return stackitem.NewStruct([]stackitem.Item{
		stackitem.NewBigInteger(big.NewInt(int64(m.ID))),
		stackitem.NewBigInteger(big.NewInt(int64(m.VitaID))),
		stackitem.NewByteArray(m.Owner.BytesBE()),
		stackitem.NewBigInteger(big.NewInt(int64(m.MilestoneType))),
		stackitem.NewByteArray([]byte(m.Title)),
		stackitem.NewByteArray([]byte(m.Description)),
		stackitem.NewByteArray(m.ContentHash.BytesBE()),
		stackitem.NewBigInteger(big.NewInt(int64(m.AchievedAt))),
		stackitem.NewBool(m.IsVerified),
	}), nil
}

// FromStackItem implements stackitem.Convertible interface.
func (m *LifeMilestone) FromStackItem(item stackitem.Item) error {
	items, ok := item.Value().([]stackitem.Item)
	if !ok {
		return errors.New("not a struct")
	}
	if len(items) != 9 {
		return fmt.Errorf("wrong number of elements: expected 9, got %d", len(items))
	}

	id, err := items[0].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid id: %w", err)
	}
	m.ID = id.Uint64()

	vitaID, err := items[1].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid vitaID: %w", err)
	}
	m.VitaID = vitaID.Uint64()

	owner, err := items[2].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid owner: %w", err)
	}
	m.Owner, err = util.Uint160DecodeBytesBE(owner)
	if err != nil {
		return fmt.Errorf("invalid owner address: %w", err)
	}

	milestoneType, err := items[3].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid milestoneType: %w", err)
	}
	m.MilestoneType = MilestoneType(milestoneType.Uint64())

	title, err := items[4].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid title: %w", err)
	}
	m.Title = string(title)

	description, err := items[5].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid description: %w", err)
	}
	m.Description = string(description)

	contentHash, err := items[6].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid contentHash: %w", err)
	}
	m.ContentHash, err = util.Uint256DecodeBytesBE(contentHash)
	if err != nil {
		return fmt.Errorf("invalid contentHash value: %w", err)
	}

	achievedAt, err := items[7].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid achievedAt: %w", err)
	}
	m.AchievedAt = uint32(achievedAt.Uint64())

	isVerified, err := items[8].TryBool()
	if err != nil {
		return fmt.Errorf("invalid isVerified: %w", err)
	}
	m.IsVerified = isVerified

	return nil
}

// LifeGoal represents a future life goal.
type LifeGoal struct {
	ID           uint64       // Unique goal ID
	VitaID       uint64       // Owner's Vita ID
	Owner        util.Uint160 // Owner's address
	Title        string       // Goal title
	Description  string       // Goal description
	TargetBlock  uint32       // Target block height for completion
	Progress     uint32       // Progress percentage (0-10000 basis points)
	Status       GoalStatus   // Goal status
	CreatedAt    uint32       // Block height when created
	CompletedAt  uint32       // Block height when completed (0 = incomplete)
}

// ToStackItem implements stackitem.Convertible interface.
func (g *LifeGoal) ToStackItem() (stackitem.Item, error) {
	return stackitem.NewStruct([]stackitem.Item{
		stackitem.NewBigInteger(big.NewInt(int64(g.ID))),
		stackitem.NewBigInteger(big.NewInt(int64(g.VitaID))),
		stackitem.NewByteArray(g.Owner.BytesBE()),
		stackitem.NewByteArray([]byte(g.Title)),
		stackitem.NewByteArray([]byte(g.Description)),
		stackitem.NewBigInteger(big.NewInt(int64(g.TargetBlock))),
		stackitem.NewBigInteger(big.NewInt(int64(g.Progress))),
		stackitem.NewBigInteger(big.NewInt(int64(g.Status))),
		stackitem.NewBigInteger(big.NewInt(int64(g.CreatedAt))),
		stackitem.NewBigInteger(big.NewInt(int64(g.CompletedAt))),
	}), nil
}

// FromStackItem implements stackitem.Convertible interface.
func (g *LifeGoal) FromStackItem(item stackitem.Item) error {
	items, ok := item.Value().([]stackitem.Item)
	if !ok {
		return errors.New("not a struct")
	}
	if len(items) != 10 {
		return fmt.Errorf("wrong number of elements: expected 10, got %d", len(items))
	}

	id, err := items[0].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid id: %w", err)
	}
	g.ID = id.Uint64()

	vitaID, err := items[1].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid vitaID: %w", err)
	}
	g.VitaID = vitaID.Uint64()

	owner, err := items[2].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid owner: %w", err)
	}
	g.Owner, err = util.Uint160DecodeBytesBE(owner)
	if err != nil {
		return fmt.Errorf("invalid owner address: %w", err)
	}

	title, err := items[3].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid title: %w", err)
	}
	g.Title = string(title)

	description, err := items[4].TryBytes()
	if err != nil {
		return fmt.Errorf("invalid description: %w", err)
	}
	g.Description = string(description)

	targetBlock, err := items[5].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid targetBlock: %w", err)
	}
	g.TargetBlock = uint32(targetBlock.Uint64())

	progress, err := items[6].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid progress: %w", err)
	}
	g.Progress = uint32(progress.Uint64())

	status, err := items[7].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid status: %w", err)
	}
	g.Status = GoalStatus(status.Uint64())

	createdAt, err := items[8].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid createdAt: %w", err)
	}
	g.CreatedAt = uint32(createdAt.Uint64())

	completedAt, err := items[9].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid completedAt: %w", err)
	}
	g.CompletedAt = uint32(completedAt.Uint64())

	return nil
}

// SeseConfig represents configurable parameters for the Sese contract.
type SeseConfig struct {
	DefaultSabbaticalCredits uint64 // Default sabbatical credits per year
	MinSabbaticalDuration    uint32 // Minimum sabbatical duration in blocks
	MaxSabbaticalDuration    uint32 // Maximum sabbatical duration in blocks
	GovernmentMatchPercent   uint32 // Government matching percentage (basis points)
	LongevityBonusPercent    uint32 // Longevity bonus percentage (basis points per year)
}

// ToStackItem implements stackitem.Convertible interface.
func (c *SeseConfig) ToStackItem() (stackitem.Item, error) {
	return stackitem.NewStruct([]stackitem.Item{
		stackitem.NewBigInteger(big.NewInt(int64(c.DefaultSabbaticalCredits))),
		stackitem.NewBigInteger(big.NewInt(int64(c.MinSabbaticalDuration))),
		stackitem.NewBigInteger(big.NewInt(int64(c.MaxSabbaticalDuration))),
		stackitem.NewBigInteger(big.NewInt(int64(c.GovernmentMatchPercent))),
		stackitem.NewBigInteger(big.NewInt(int64(c.LongevityBonusPercent))),
	}), nil
}

// FromStackItem implements stackitem.Convertible interface.
func (c *SeseConfig) FromStackItem(item stackitem.Item) error {
	items, ok := item.Value().([]stackitem.Item)
	if !ok {
		return errors.New("not a struct")
	}
	if len(items) != 5 {
		return fmt.Errorf("wrong number of elements: expected 5, got %d", len(items))
	}

	defaultCredits, err := items[0].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid defaultSabbaticalCredits: %w", err)
	}
	c.DefaultSabbaticalCredits = defaultCredits.Uint64()

	minDuration, err := items[1].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid minSabbaticalDuration: %w", err)
	}
	c.MinSabbaticalDuration = uint32(minDuration.Uint64())

	maxDuration, err := items[2].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid maxSabbaticalDuration: %w", err)
	}
	c.MaxSabbaticalDuration = uint32(maxDuration.Uint64())

	govMatch, err := items[3].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid governmentMatchPercent: %w", err)
	}
	c.GovernmentMatchPercent = uint32(govMatch.Uint64())

	longevityBonus, err := items[4].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid longevityBonusPercent: %w", err)
	}
	c.LongevityBonusPercent = uint32(longevityBonus.Uint64())

	return nil
}
