package model

import (
	"errors"
	"fmt"
	"go-nkode/util"
)

type CustomerAttributes struct {
	AttrVals []uint64
	SetVals  []uint64
}

func NewCustomerAttributes() (*CustomerAttributes, error) {
	attrVals, errAttr := util.GenerateRandomNonRepeatingUint64(KeypadMax.TotalAttrs())
	if errAttr != nil {
		return nil, errAttr
	}
	setVals, errSet := util.GenerateRandomNonRepeatingUint64(KeypadMax.AttrsPerKey)
	if errSet != nil {
		return nil, errSet
	}

	customerAttrs := CustomerAttributes{
		AttrVals: attrVals,
		SetVals:  setVals,
	}
	return &customerAttrs, nil
}

func NewCustomerAttributesFromBytes(attrBytes []byte, setBytes []byte) CustomerAttributes {
	return CustomerAttributes{
		AttrVals: util.ByteArrToUint64Arr(attrBytes),
		SetVals:  util.ByteArrToUint64Arr(setBytes),
	}
}

func (c *CustomerAttributes) Renew() error {
	attrVals, errAttr := util.GenerateRandomNonRepeatingUint64(KeypadMax.TotalAttrs())
	if errAttr != nil {
		return errAttr
	}
	setVals, errSet := util.GenerateRandomNonRepeatingUint64(KeypadMax.AttrsPerKey)
	if errSet != nil {
		return errSet
	}
	c.AttrVals = attrVals
	c.SetVals = setVals
	return nil
}

func (c *CustomerAttributes) IndexOfAttr(attrVal uint64) int {
	// TODO: should this be mapped instead?
	return util.IndexOf[uint64](c.AttrVals, attrVal)
}

func (c *CustomerAttributes) IndexOfSet(setVal uint64) (int, error) {
	// TODO: should this be mapped instead?
	idx := util.IndexOf[uint64](c.SetVals, setVal)
	if idx == -1 {
		return -1, errors.New(fmt.Sprintf("Set Val %d is invalid", setVal))
	}
	return idx, nil
}

func (c *CustomerAttributes) GetAttrSetVal(attrVal uint64, userKeypad KeypadDimension) (uint64, error) {
	indexOfAttr := c.IndexOfAttr(attrVal)
	if indexOfAttr == -1 {
		return 0, errors.New(fmt.Sprintf("No attribute %d", attrVal))
	}
	setIdx := indexOfAttr % userKeypad.AttrsPerKey
	return c.SetVals[setIdx], nil
}

func (c *CustomerAttributes) AttrValsForKp(userKp KeypadDimension) ([]uint64, error) {
	err := userKp.IsValidKeypadDimension()
	if err != nil {
		return nil, err
	}
	return c.AttrVals[:userKp.TotalAttrs()], nil
}

func (c *CustomerAttributes) SetValsForKp(userKp KeypadDimension) ([]uint64, error) {
	err := userKp.IsValidKeypadDimension()
	if err != nil {
		return nil, err
	}
	return c.SetVals[:userKp.AttrsPerKey], nil
}

func (c *CustomerAttributes) AttrBytes() []byte {
	return util.Uint64ArrToByteArr(c.AttrVals)
}

func (c *CustomerAttributes) SetBytes() []byte {
	return util.Uint64ArrToByteArr(c.SetVals)
}
