#pragma once

#include <cstddef>
#include <stdexcept>
#include <type_traits>
namespace zt {
    template<class T>
    class Stack{
    private:
        using valueType = std::remove_cv_t<T>;
        size_t stackSize{};
        struct Node{
            valueType value;
            Node* previous;
        };
        Node *topNode{nullptr};
    public:
        constexpr explicit Stack(){}
        constexpr size_t size()const noexcept{
            return stackSize;
        }
        constexpr valueType top()const{
            if(topNode==nullptr){
                throw std::runtime_error("the top of the struct stack is nullptr");
            }
            return topNode->value;
        }
        constexpr bool empty()const noexcept{
            return topNode == nullptr;
        }
        constexpr Stack& push(valueType const& val)noexcept{
            Node* newNode = new Node{};
            newNode->value = val;
            stackSize++;
            if(topNode==nullptr){
                topNode = newNode;
            }else{
                newNode->previous = topNode;
                topNode = newNode;
            }
            return *this;
        }
        constexpr Stack& pop(){
            if(topNode==nullptr){
                throw std::runtime_error("the top of the stack is nullptr");
            }
            stackSize--;
            Node* oldNode{topNode};
            topNode=topNode->previous;
            delete oldNode;
            return *this;
        }
        ~Stack(){
            while (topNode!=nullptr) {
                pop();
            }
        }
    };
}