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"
)

// LifeStage represents age-based life stages.
type LifeStage uint8

const (
	// LifeStageChild indicates ages 0-17 years.
	LifeStageChild LifeStage = 0
	// LifeStageYouth indicates ages 18-25 years.
	LifeStageYouth LifeStage = 1
	// LifeStageAdult indicates ages 26-64 years.
	LifeStageAdult LifeStage = 2
	// LifeStageElder indicates ages 65+ years.
	LifeStageElder LifeStage = 3
)

// LifespanStatus represents the living status of a person.
type LifespanStatus uint8

const (
	// LifespanActive indicates the person is alive.
	LifespanActive LifespanStatus = 0
	// LifespanDeceased indicates the person has passed away.
	LifespanDeceased LifespanStatus = 1
)

// LifespanRecord tracks a person's lifespan tied to their Vita.
type LifespanRecord struct {
	VitaID            uint64         // Owner's Vita token ID
	Owner             util.Uint160   // Owner's address
	BirthTimestamp    uint64         // Unix timestamp of actual birth (provided during registration)
	RegistrationBlock uint32         // Block height when Vita was minted
	RegistrationTime  uint64         // Timestamp when Vita was minted
	DeathTimestamp    uint64         // 0 = alive, >0 = time of death
	DeathBlock        uint32         // 0 = alive, >0 = block when death recorded
	Status            LifespanStatus // Current lifespan status
}

// ToStackItem implements stackitem.Convertible interface.
func (r *LifespanRecord) ToStackItem() (stackitem.Item, error) {
	return stackitem.NewStruct([]stackitem.Item{
		stackitem.NewBigInteger(big.NewInt(int64(r.VitaID))),
		stackitem.NewByteArray(r.Owner.BytesBE()),
		stackitem.NewBigInteger(new(big.Int).SetUint64(r.BirthTimestamp)),
		stackitem.NewBigInteger(big.NewInt(int64(r.RegistrationBlock))),
		stackitem.NewBigInteger(new(big.Int).SetUint64(r.RegistrationTime)),
		stackitem.NewBigInteger(new(big.Int).SetUint64(r.DeathTimestamp)),
		stackitem.NewBigInteger(big.NewInt(int64(r.DeathBlock))),
		stackitem.NewBigInteger(big.NewInt(int64(r.Status))),
	}), nil
}

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

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

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

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

	registrationBlock, err := items[3].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid registrationBlock: %w", err)
	}
	r.RegistrationBlock = uint32(registrationBlock.Int64())

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

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

	deathBlock, err := items[6].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid deathBlock: %w", err)
	}
	r.DeathBlock = uint32(deathBlock.Int64())

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

	return nil
}

// AnnosConfig represents configurable parameters for the Annos contract.
type AnnosConfig struct {
	VotingAge     uint8  // Age required to vote (default: 18)
	AdultAge      uint8  // Age of legal adulthood (default: 18)
	RetirementAge uint8  // Age of retirement eligibility (default: 65)
	YouthMaxAge   uint8  // Maximum age for youth stage (default: 25)
	ElderMinAge   uint8  // Minimum age for elder stage (default: 65)
}

// ToStackItem implements stackitem.Convertible interface.
func (c *AnnosConfig) ToStackItem() (stackitem.Item, error) {
	return stackitem.NewStruct([]stackitem.Item{
		stackitem.NewBigInteger(big.NewInt(int64(c.VotingAge))),
		stackitem.NewBigInteger(big.NewInt(int64(c.AdultAge))),
		stackitem.NewBigInteger(big.NewInt(int64(c.RetirementAge))),
		stackitem.NewBigInteger(big.NewInt(int64(c.YouthMaxAge))),
		stackitem.NewBigInteger(big.NewInt(int64(c.ElderMinAge))),
	}), nil
}

// FromStackItem implements stackitem.Convertible interface.
func (c *AnnosConfig) 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))
	}

	votingAge, err := items[0].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid votingAge: %w", err)
	}
	c.VotingAge = uint8(votingAge.Int64())

	adultAge, err := items[1].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid adultAge: %w", err)
	}
	c.AdultAge = uint8(adultAge.Int64())

	retirementAge, err := items[2].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid retirementAge: %w", err)
	}
	c.RetirementAge = uint8(retirementAge.Int64())

	youthMaxAge, err := items[3].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid youthMaxAge: %w", err)
	}
	c.YouthMaxAge = uint8(youthMaxAge.Int64())

	elderMinAge, err := items[4].TryInteger()
	if err != nil {
		return fmt.Errorf("invalid elderMinAge: %w", err)
	}
	c.ElderMinAge = uint8(elderMinAge.Int64())

	return nil
}

// DefaultAnnosConfig returns the default configuration for Annos.
func DefaultAnnosConfig() AnnosConfig {
	return AnnosConfig{
		VotingAge:     18,
		AdultAge:      18,
		RetirementAge: 65,
		YouthMaxAge:   25,
		ElderMinAge:   65,
	}
}
