package inn.ocsf.bee.freigeld.core.model.data;

import com.querydsl.core.annotations.QueryEntity;
import inn.ocsf.bee.freigeld.core.model.Coin;
import inn.ocsf.bee.freigeld.core.model.CoinValue;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.UUID;

@Document("coin")
public class CoinData {

    @Id
    private ObjectId id;

    private CoinImpl coin;

    private CoinStatus status;

    @Version
    private Long version;

    public ObjectId getId() {
        return id;
    }

    public void setId(ObjectId id) {
        this.id = id;
    }

    public CoinStatus getStatus() {
        return status;
    }

    public void setStatus(CoinStatus status) {
        this.status = status;
    }

    public Coin getCoin() {
        return coin;
    }

    public void setCoin(Coin coin) {
        if (coin instanceof CoinImpl) {
            this.coin = (CoinImpl) coin;
        } else if (coin != null) {
            throw new RuntimeException("not suppoted coin impl");
        } else {
            this.coin = null;
        }
    }

    @QueryEntity
    public static class CoinImpl implements Coin {

        private UUID id;

        private int era;

        private CoinValue value;

        private Long amount;

        public CoinImpl() {
        }

        public CoinImpl(CoinValue value, int era) {
            this.id = UUID.randomUUID();
            this.era = era;
            this.value = value;
            this.amount = getCurrent();
        }

        public CoinImpl(UUID id, int era, CoinValue value) {
            this.id = id;
            this.era = era;
            this.value = value;
            this.amount = getCurrent();
        }

        @Override
        public UUID getId() {
            return id;
        }

        public void setId(UUID id) {
            this.id = id;
        }

        @Override
        public int getEra() {
            return era;
        }

        public void setEra(int era) {
            this.era = era;
            this.amount = getCurrent();
        }

        @Override
        public void incEra() {
            this.era = Long.valueOf(Math.min(CoinValue.MAX_ERA, this.era + 1)).intValue();
            this.amount = getCurrent();
        }

        @Override
        public CoinValue getValue() {
            return value;
        }

        public void setValue(CoinValue value) {
            this.value = value;
            this.amount = getCurrent();
        }

        public Long getAmount() {
            if (amount == null) {
                amount = getCurrent();
            }
            return amount;
        }
    }
}
