//
//  YCKLoginManagerProtocol.h
//  YCKSdwan
//
//  Created by 徐家骏 on 2019/6/17.
//  Copyright © 2019 徐家骏. All rights reserved.
//
#pragma once
#ifndef YCKLoginManagerProtocol_h
#define YCKLoginManagerProtocol_h

#ifdef SDK_SIMPLE_INCLUDE
#include "common.h"
#else
#include <YCKSdwan/common.h>
#endif
#include "YCKAccount.h"
#include "YCKKickInfo.h"
#include <unordered_map>
/**
 *  登录服务相关Block
 *
 *  @param error 执行结果,如果成功error为nil
 */
typedef std::function<void (int)> YCKLoginHandler;

/**
 *  登录步骤枚举
 */
enum YCKLoginStep
{
    /**
     *  登录
     */
    YCKLoginStepLogining = 1,
    /**
     *  登录成功
     */
    YCKLoginStepLoginOK,

    /**
     *  开始同步
     */
    YCKLoginStepSyncing,
    /**
     *  同步完成
     */
    YCKLoginStepSyncOK,
    /**
	 * Actually refresh token
     */
    YCKLoginStepAutoLogining,
    /**
     *
     */
    YCKLoginStepAutoLoginOk
};

enum YCKCallbackType {
    onLogin = 1,
    onLoginFailed,
    onKick,
    onLogout,
    onRefreshToken,
    onRefreshTokenFailed
};

#ifndef NDEBUG
enum YCKLoginMode{
    FakeLogin = 1,
    RealLogin
};
#endif


/**
 *  登录相关回调
 */
class YCKLoginManagerDelegate {

public:
/**
 *  被踢(服务器/其他端)回调
 *
 *  @param kickInfo        被踢原因
 */
	virtual void onKick(const YCKKickInfo& kickInfo)=0;


/**
 *  登录回调
 *
 *  @param step 登录步骤
 *  @discussion 这个回调主要用于客户端UI的刷新
 */
virtual void onLogin(YCKLoginStep step)=0;

/**
 *  自动登录失败回调
 *
 *  @param error 失败原因
 *  @discussion 自动重连不需要上层开发关心，但是如果发生一些需要上层开发处理的错误，SDK 会通过这个方法回调
 *              用户需要处理的情况包括：AppKey 未被设置，参数错误，密码错误，多端登录冲突，账号被封禁，操作过于频繁等
 */
virtual void onLoginFailed(int error)=0;

///**
// *  多端登录发生变化
// */
//- (void)onMultiLoginClientsChanged;


virtual void onLogout()=0;

virtual ~YCKLoginManagerDelegate()=default;
};


/**
 *  登录协议
 */
class YCKLoginManager{
public:
#ifndef NDEBUG
    YCKLoginMode loginMode = RealLogin;
#endif


	virtual	void init()=0;
	
	virtual void loginDirect(int64_t rid, std::string accountId, YCKLoginHandler completion) = 0;

/**
 *  登录
 *
 *  @param account    帐号
 *  @param rid        客户端绑定账号时用的rid
 *  @param completion 完成回调
 *
 */
virtual void login(int64_t account,int64_t rid,std::string accountSecret,
		std::unordered_map<std::string,std::string> parameters,
		YCKLoginHandler completion)=0;
/**
 *  机器人登录 目前用于双摄
 *
 *  @param account    帐号
 *  @param rid        客户端绑定账号时用的rid
 *  @param completion 完成回调
 *
 */
virtual void robotLogin(int64_t account, int64_t rid, YCKLoginHandler completion) = 0;

virtual void refreshToken() = 0;
///**
// @discussion token过期后刷新token
// */
//- (void)updateTokenCompletion:(YCKLoginHandler)completion;
/**
 *  登出
 *
 *  @param completion 完成回调
 *  @discussion 用户在登出是需要调用这个接口进行 SDK 相关数据的清理,如果网络错误导致服务器没有收到登出请求, 将返回失败。
 *
 */
virtual void logout(YCKLoginHandler completion)=0;

/**
 *  强制登出
 *
 *  @param completion 完成回调
 *  @param forceMode 如果是YES, 如用户登出时发生网络错误导致服务器没有收到登出请求，客户端仍可以登出(切换界面，清理数据等)，但会出现推送信息仍旧会发到当前手机的问题。返回信息里还是会带网络访问错误.
 *  @discussion 用户在登出是需要调用这个接口进行 SDK 相关数据的清理,回调 Block 中的 error 只是指明和服务器的交互流程中可能出现的错误。
 */
virtual void logout(YCKLoginHandler completion, BOOL forceMode)=0;

///**
// *  踢人
// *
// *  @param client     当前登录的其他客户端
// *  @param completion 完成回调
// */
//- (void)kickOtherClient:(YCKLoginClient *)client
//             completion:(nullable YCKLoginHandler)completion;

/**
 *  返回当前登录帐号
 *
 *  @return 当前登录帐号。如果没有上次登陆记录，会返回0。若有，且正在自动登陆过程中，此处返回上次登陆uid
 */
virtual int64_t currentAccount() const=0;


virtual const YCKAccount& activeAccount() const=0;

virtual uint64_t deltaTimeOfLocalAndServer()=0;
/**
 *  当前登录状态。
 *  注意，刚启动时，若自动登陆还未完成，此处也返回false。但是currentAccount会有值。
 *  这时可以注册LoginManagerDelegate，监听自动登陆结果。
 *  @return 当前登录状态
 */
virtual BOOL hasLogin()=0;

///**
// *  返回当前登录的设备列表
// *
// *  @return 当前登录设备列表 内部是YCKLoginClient,不包括自己
// */
//- (nullable NSArray<YCKLoginClient *> *)currentLoginClients;


/**
 *  添加登录委托
 *
 *  @param delegate 登录委托
 */
virtual void addDelegate(std::shared_ptr<YCKLoginManagerDelegate> delegate)=0;

/**
 *  移除登录委托
 *
 *  @param delegate 登录委托
 */
virtual void removeDelegate(std::shared_ptr<YCKLoginManagerDelegate> delegate)=0;

virtual ~YCKLoginManager()=default;
};

#endif /* YCKLoginManagerProtocol_h */
