package core

import (
	"github.com/google/uuid"
	"go-nkode/hashset"
	"go-nkode/util"
)

type Customer struct {
	Id          CustomerId
	NKodePolicy NKodePolicy
	Attributes  CustomerAttributes
}

func NewCustomer(nkodePolicy NKodePolicy) (*Customer, error) {
	customerAttrs, err := NewCustomerAttributes()
	if err != nil {
		return nil, err
	}
	customer := Customer{
		Id:          CustomerId(uuid.New()),
		NKodePolicy: nkodePolicy,
		Attributes:  *customerAttrs,
	}

	return &customer, nil
}

func (c *Customer) IsValidNKode(kp KeypadDimension, passcodeAttrIdx []int) error {
	nkodeLen := len(passcodeAttrIdx)
	if nkodeLen < c.NKodePolicy.MinNkodeLen || nkodeLen > c.NKodePolicy.MaxNkodeLen {
		return ErrInvalidNKodeLength
	}

	if validIdx := kp.ValidateAttributeIndices(passcodeAttrIdx); !validIdx {
		return ErrInvalidNKodeIdx
	}
	passcodeSetVals := make(hashset.Set[uint64])
	passcodeAttrVals := make(hashset.Set[uint64])
	attrVals, err := c.Attributes.AttrValsForKp(kp)
	if err != nil {
		return err
	}
	for idx := 0; idx < nkodeLen; idx++ {
		attrVal := attrVals[passcodeAttrIdx[idx]]
		setVal, err := c.Attributes.GetAttrSetVal(attrVal, kp)
		if err != nil {
			return err
		}
		passcodeSetVals.Add(setVal)
		passcodeAttrVals.Add(attrVal)
	}

	if passcodeSetVals.Size() < c.NKodePolicy.DistinctSets {
		return ErrTooFewDistinctSet
	}

	if passcodeAttrVals.Size() < c.NKodePolicy.DistinctAttributes {
		return ErrTooFewDistinctAttributes
	}
	return nil
}

func (c *Customer) RenewKeys() ([]uint64, []uint64, error) {
	oldAttrs := make([]uint64, len(c.Attributes.AttrVals))
	oldSets := make([]uint64, len(c.Attributes.SetVals))

	copy(oldAttrs, c.Attributes.AttrVals)
	copy(oldSets, c.Attributes.SetVals)

	if err := c.Attributes.Renew(); err != nil {
		return nil, nil, err
	}
	attrsXor, err := util.XorLists(oldAttrs, c.Attributes.AttrVals)
	if err != nil {
		return nil, nil, err
	}
	setXor, err := util.XorLists(oldSets, c.Attributes.SetVals)
	if err != nil {
		return nil, nil, err
	}
	return setXor, attrsXor, nil
}
