//
//  Copyright © 2017 IPsoft. All rights reserved.
//

#import "IPSAKDownloadMessage.h"
#import "IPSAKMessage.h"
#import "IPSAKObject.h"

NS_ASSUME_NONNULL_BEGIN

@class IPSAKUploadMessage;
@class IPSStompClient;
@class IPSAKFormInputData;
@class IPSAKBpnExecutionEvent;
@protocol IPSAKConversationDelegate;

typedef NS_ENUM(NSInteger, IPSAKConversationState) {
    IPSAKConversationConnecting,
    IPSAKConversationConnected,
    /// `endConversation` has been called.
    IPSAKConversationEnding,
    IPSAKConversationEnded,
    IPSAKConversationRecoverable
};

/**
 An `IPSAKConversation` instance is created when a new conversation starts.
 */
@interface IPSAKConversation : IPSAKObject

/**
 Initializes a conversation with supplied dictionary.
 
 @param dictionary The JSON-response obtained when calling `conversation/new`.
 @param error If the passed in dictionary doesn't contain the required fields an `NSError` object with code 
 `IPSAKErrorRequiredFieldMissing` that indicates which field is missing.
 
 @return An `IPSAKConversation` instance or `nil` if the passed in dictionary is faulty.
 */
- (instancetype)initWithJSON:(NSDictionary *)dictionary error:(NSError **)error;

/// The `IPSStompClient` that should be used to send and receive the Stomp frames.
@property (strong) IPSStompClient *stompClient;

/// The object that acts as the conversation delegate.
@property (nonatomic, weak) id<IPSAKConversationDelegate> delegate;

/// The id of the conversation. Passed in during object initialization.
@property (nonatomic, readonly) NSString* conversationId;
/// The id of the conversation as a string. Passed in during object initialization.
//@property (nonatomic, copy, readonly) NSString *conversationIdString;
/// The id fo the session. Passed in during object initialization.
@property (nonatomic, readonly) NSString* sessionId;
/// The current status of whether Amelia accepts input or not.
@property (nonatomic, readonly, getter=isInputEnabled) BOOL inputEnabled;
/// The current status of whether Amelia accepts input or not.
@property (nonatomic, readonly, getter=isInputSecured) BOOL inputSecured;
/// The timestamp the last message was sent to the server.
@property (nonatomic, strong, readonly) NSDate *timeOfLastMessage;
/// Amelia's current mood.
@property (nonatomic, readonly) IPSAKMoodType currentMood;
/// The name of `Amelia`.
@property (nonatomic, copy, readonly) NSString *conversationPartnerName;
/**
 The minimum time (in milliseconds) between messages before the user is considered idle. Default: 300000 (5 minutes)
 */
@property (nonatomic) NSInteger minIdleTime;

/**
 Adds a variable time component (in milliseconds) to the min idle time. Default: 600000 (10 minutes)
 */
@property (nonatomic) NSInteger varIdleTime;

/**
 Current state of the conversation. Default: `IPSAKConversationConnecting`.
 */
@property (readonly) IPSAKConversationState conversationState;

/**
 Delegate calls are dispatched on this queue. If `nil`, the main queue is used for delegate calls.
 */
@property (strong, nonatomic, nullable) dispatch_queue_t delegateDispatchQueue;

/**
 Starts a new conversation by opening a Stomp connection to Amelia. When Amelia responds with a CONNECTED command, the
 `delegate` is sent the `conversationDidStart:` message.
 */
- (void)start;

/**
 Reconnect a disconnected session.
 */
- (void)reconnect;

/// Sends a text message to Amelia. Secure messages which should be secured.
- (void)ask:(NSString *)message;
/// Alias for `ask:`
- (void)say:(NSString *)message;

-(void)sendCustomConversationAttributes:(NSDictionary*) attributes;

/**
 Submit a form to Amelia.
 
 @note This method should be uses to respond to a message that includes `formInputData`

 @param form The form included in the message.¯
 @param message The text to speak in the submission
 */
- (void)submitForm:(IPSAKFormInputData *)form message:(NSString *_Nullable)message;

/**
 Run the named BPN process on Amelia.
 
 @param processName The name of the BPN process to run.
 @param processArgs The arguments to pass to the process.
 @param message A custom message to send.
 */
- (void)runAction:(NSString *)processName arguments:(NSDictionary *)processArgs message:(NSString *)message;
/**
 send file upload confirmation message after upload finished
 
 @param submited true if the upload was successful
 */
-(void)sendFileUploadConfirmationMessage:(BOOL)submited;

/**
 Ends the current conversation.
 */
- (void)endConversation;

@end

/**
 The `IPSAKConversationDelegate` protocol defines the optional methods you implement to make a chat session functional.
 */
@protocol IPSAKConversationDelegate<NSObject>

@optional
/**
 Tells the delegate that a conversation has been started. This is response to a Stomp session being established to Amelia.
 */
- (void)conversationDidStart:(IPSAKConversation *)conversation;
/**
 Tells the delegate the conversation has ended.
 @param conversation The conversation object informing the delegate of this event.
 */
- (void)conversationDidEnd:(IPSAKConversation *)conversation;
/**
 Tells the delegate that then conversation is connected.
 */
- (void)conversationDidConnect:(IPSAKConversation *)conversation;
/**
 Tells the delegate that then conversation is disconnected unexpectedly.
 */
- (void)conversationDidDisconnect:(IPSAKConversation *)conversation;
/**
 Tells the delegate that the conversation is reconnected after a previous disconnect.
 */
- (void)conversationDidReconnect:(IPSAKConversation *)conversation;
/**
 Tells the delegate that a message has been received from Amelia.
 */
- (void)conversation:(IPSAKConversation *)conversation didReceiveMessage:(IPSAKMessage *)message;
/**
 Tells the delegate that an multimedia message has been received from Amelia.
 */
- (void)conversation:(IPSAKConversation *)conversation didReceiveDownloadMessage:(IPSAKDownloadMessage *)message;
/**
 Tells the delegate that an upload is requested.
 */
- (void)conversation:(IPSAKConversation *)conversation uploadRequested:(IPSAKUploadMessage *)uploadRequest;
/**
 Tells the delegate that an upload has successfully completed.
 */
- (void)conversationUploadSuccess:(IPSAKConversation *)conversation;
/**
 Tells the delegate that an upload failed.
 */
- (void)conversation:(IPSAKConversation *)conversation uploadFailWithError:(NSError *)error;
/**
 Tells the delegate whether Amelia is ready to receive input or not.
 */
- (void)conversation:(IPSAKConversation *)conversation inputEnabled:(BOOL)enabled;
/**
 Tells the delegate whether the user's input needs to be secured.
 */
- (void)conversation:(IPSAKConversation *)conversation inputSecured:(BOOL)enabled;
/**
 Tells the delegate that input is currently blocked.
 */
- (void)conversationErrorInputBlocked:(IPSAKConversation *)conversation;
/**
 Tells the delegate that the conversation is now idle.
 */
- (void)conversationIdle:(IPSAKConversation *)conversation;
/**
 Tells the delegate that Amelia's mood has changed.
 */
- (void)conversation:(IPSAKConversation *)conversation moodChangeFrom:(IPSAKMoodType)fromMood to:(IPSAKMoodType)toMood;
/**
 Tells the delegate that an error occurred while chatting.
 */
- (void)conversation:(IPSAKConversation *)conversation error:(NSError *)error;
/**
 Tells the delegate that the conversation has been disconnected.
 */
- (void)conversation:(IPSAKConversation *)conversation didDisconnectWithError:(NSError *)error;

@end

NS_ASSUME_NONNULL_END
