#ifndef LIP_OPCUA_SERVER_SUBSCRIPTIONS_H
#define LIP_OPCUA_SERVER_SUBSCRIPTIONS_H

#include "lip/app/opcua/server/lip_opcua_server_cfg_defs.h"
#include "lip/app/opcua/types/lip_opcua_base_types.h"
#include "lip_opcua_server_monitem.h"
#include "ltimer.h"

typedef enum {
    LIP_OPCUA_SRVSUB_STATE_CLOSED   = 0, /* The Subscription has not yet been created or has terminated. */
    LIP_OPCUA_SRVSUB_STATE_NORMAL   = 2, /* The Subscription is cyclically checking for Notifications from its MonitoredItems. The keep-alive counter is not used in this state. */
    LIP_OPCUA_SRVSUB_STATE_LATE     = 3, /* The publishing timer has expired and there are Notifications available or a keep-alive
                                            Message is ready to be sent, but there are no Publish requests queued. When in this state, the next Publish
                                            request is processed when it is received. The keep-alive counter is not used in this state.. */
    LIP_OPCUA_SRVSUB_STATE_KEEPALIVE= 4, /* The Subscription is cyclically checking for Notifications from its MonitoredItems or for the keep-alive counter to count down to 0 from its maximum. */
} t_lip_opcua_srvsub_state;


typedef enum {
    LIP_OPCUA_SRVSUB_FLAG_PUB_ENABLED     = 1 << 0,
    LIP_OPCUA_SRVSUB_FLAG_FIRST_MSG_SENT  = 1 << 1,
    LIP_OPCUA_SRVSUB_FLAG_MORE_NOTICATION = 1 << 2,
} t_lip_opcua_srvsub_flags;

struct st_lip_opcua_session_ctx;


typedef struct st_lip_opcua_srvsub_ctx {
    t_lip_opcua_srvsub_state state;
    t_lip_opcua_intid id;
    t_lip_opcua_counter next_seqnum;
    uint16_t flags;
    uint8_t  maxKeepAliveCnt;
    uint8_t  curKeepAliveCnt;
    int pubRdyNotification;
    t_lip_opcua_counter  maxLifetimeCnt;
    t_lip_opcua_counter  curLifetimeCnt;
    t_lip_opcua_counter  maxNotificationPerPublish;


    t_ltimer pub_tmr;

    t_lip_opcua_monitem_ctx *monitems[LIP_OPCUA_SERVER_SUB_MONITEM_MAX_CNT];
    uint16_t monitems_cnt;
    uint16_t monitem_pubreq_pos;
} t_lip_opcua_srvsub_ctx;






typedef struct {
    t_lip_opcua_duration pubInterval;
    t_lip_opcua_counter  lifetimeCnt;
    t_lip_opcua_counter  maxKeepAliveCnt;
    t_lip_opcua_counter  maxNotificationPerPublish;
    uint8_t              priority;
} t_lip_opcua_subscription_params;

t_lip_opcua_err lip_opcua_server_sub_create(t_lip_opcua_srvsub_ctx *sub, t_lip_opcua_subscription_params *params, bool publish_en);
void lip_opcua_server_sub_delete(t_lip_opcua_srvsub_ctx *sub);
t_lip_opcua_err lip_opcua_server_sub_set_params(t_lip_opcua_srvsub_ctx *sub, t_lip_opcua_subscription_params *params);
t_lip_opcua_err lip_opcua_server_sub_set_publish_en(t_lip_opcua_srvsub_ctx *sub, bool en);

void lip_opcua_server_sub_pull(t_lip_opcua_srvsub_ctx *sub, struct st_lip_opcua_session_ctx *session);
void lip_opcua_server_sub_proc_publish(t_lip_opcua_srvsub_ctx *sub, struct st_lip_opcua_session_ctx *session);

static LINLINE uint32_t lip_opcua_server_sub_publish_interval(const t_lip_opcua_srvsub_ctx *sub) {
    return ltimer_interval_ms(&sub->pub_tmr);
}

t_lip_opcua_err lip_opcua_server_sub_monitem_create(t_lip_opcua_srvsub_ctx *sub, struct st_lip_opcua_session_ctx *session,
                                                    t_lip_opcua_monitem_create_params *params, t_lip_opcua_intid *monitem_id);
t_lip_opcua_err lip_opcua_server_sub_monitem_delete(t_lip_opcua_srvsub_ctx *sub, t_lip_opcua_intid monitem_id);
t_lip_opcua_err lip_opcua_server_sub_monitem_get(t_lip_opcua_srvsub_ctx *sub, t_lip_opcua_intid monitem_id,  t_lip_opcua_monitem_ctx **pmonitem);



#endif // LIP_OPCUA_SERVER_SUBSCRIPTIONS_H
