#pragma once

#include <date.h>
#include <experimental/optional>
#include <experimental/string_view>
#include <memory>
#include <string>
#include <vector>

namespace eedb {

class Item {};

class ItemStorageRoom {};

class UserConfig {};

/// utils
class EmailVerifier {
  public:
    using string_view = std::experimental::string_view;

  public:
    enum class Status { Good, Bad };
    virtual ~EmailVerifier() = 0;

    virtual Status verify(string_view) const = 0;
};

class Email {
  protected:
    using string_view = std::experimental::string_view;
    using string      = std::string;

  public:
    Email(string email) : _data(std::move(email)) {}
    virtual ~Email() = default;

    virtual bool isValid() const {
        return true;
    }

    virtual bool isEmpty() const {
        return _data.empty();
    }

    virtual operator string_view() const {
        return _data;
    }

  private:
    string _data;
};

class UserPassword {
  protected:
    using string_view = std::experimental::string_view;
    using string      = std::string;

    virtual void hash() = 0;

  public:
    virtual ~UserPassword() = default;

    virtual string_view value() const    = 0;
    virtual string_view function() const = 0;
    virtual string_view salt() const     = 0;
};

/// user data

class UserName {
  protected:
    using string_view = std::experimental::string_view;
    using string      = std::string;

  public:
    virtual ~UserName() = default;

    virtual bool isValid() const = 0;

    virtual operator string_view() const = 0;
};

class AuthIdentity {
  protected:
    using string_view = std::experimental::string_view;
    using string      = std::string;

  public:
    virtual ~AuthIdentity() = default;

    virtual string_view identity() const = 0;
    virtual string_view provider() const = 0;
};

class AuthInfo {
  protected:
    using string_view = std::experimental::string_view;
    using string      = std::string;

  public:
    virtual ~AuthInfo() = default;

    virtual const Email & email() const = 0;
    virtual void email(string email)    = 0;

    virtual bool emailVerified() const = 0;
    virtual void verifyEmail()         = 0;
    virtual bool isUnique() const      = 0;
};

class User {
  public:
    template < typename T >
    using optional = std::experimental::optional< T >;
    using string   = std::string;

    using ItemStorage = std::weak_ptr< ItemStorageRoom >;

    using ItemStorages = std::vector< ItemStorage >;

    using StorageCreateError = std::string;

  public:
    virtual ~User() = default;

    // user identity
    virtual int uid() const                       = 0;
    virtual const AuthIdentity & identity() const = 0;
    virtual const AuthInfo & authInfo() const     = 0;

    // user configuration
    virtual const UserConfig & config() const = 0;
    virtual UserConfig & config()             = 0;

    // user auth
    virtual void changePassword(UserPassword & password) = 0;
    virtual void login(UserPassword & password)          = 0;
    virtual void logout()                                = 0;
};
}
