#include "ring_app.h"
#include <string.h>

static bool power_ok(const struct ring_app *a) {
    return a->in.battery_valid && a->in.battery_mv >= 3400 && a->in.battery_mv <= 4250;
}
static bool link_ok(const struct ring_app *a) {
    return a->in.connected && a->in.encrypted;
}
void ring_init(struct ring_app *a, uint32_t now) {
    memset(a,0,sizeof(*a)); a->mode=RING_LOW_BATTERY; a->last_health=now;
}
void ring_inputs_set(struct ring_app *a, struct ring_inputs in, uint32_t now) {
    a->in=in; ring_tick(a,now);
}
void ring_local_consent(struct ring_app *a, uint32_t now) {
    if (a->mode==RING_IDLE && power_ok(a) && link_ok(a)) {
        a->consent=true; a->consent_at=now;
    }
}
enum ring_result ring_command(struct ring_app *a,const uint8_t *d,size_t n,uint32_t now) {
    ring_tick(a,now);
    if (!d || n<1) return RING_INVALID;
    if (!link_ok(a)) return RING_DENIED;
    switch(d[0]) {
    case 1: { /* start PCM clip, duration little endian */
        if(n!=3) return RING_INVALID;
        uint16_t ms=(uint16_t)((uint16_t)d[1]|((uint16_t)d[2]<<8));
        if(ms<100 || ms>RING_CLIP_MAX_MS) return RING_INVALID;
        if(a->mode!=RING_IDLE) return RING_BUSY;
        if(!power_ok(a) || !a->in.subscribed || !a->consent || (uint32_t)(now-a->consent_at)>=RING_CONSENT_MS) return RING_DENIED;
        a->consent=false; a->clip_ms=ms; a->mode=RING_RECORDING;
        a->mode_started=now; ++a->clip_id; return RING_OK;
    }
    case 2: /* stop; authorization token is consumed even if already idle */
        if(n!=1) return RING_INVALID;
        a->consent=false;
        if(a->mode==RING_RECORDING || a->mode==RING_MEASURING) a->mode=RING_IDLE;
        a->health_requested=false; a->manual_health=false;
        return RING_OK;
    case 3:
        if(n!=1) return RING_INVALID;
        if(a->mode!=RING_IDLE) return RING_BUSY;
        if(!power_ok(a) || (!a->in.worn && !a->consent)) return RING_DENIED;
        a->manual_health=!a->in.worn;
        a->health_requested=true; ring_tick(a,now); return RING_OK;
    default: return RING_INVALID;
    }
}
void ring_tick(struct ring_app *a,uint32_t now) {
    if(a->in.fault) a->mode=RING_FAULT;
    else if(a->in.charging) a->mode=RING_CHARGING;
    else if(!power_ok(a)) a->mode=RING_LOW_BATTERY;
    else if(a->mode==RING_FAULT || a->mode==RING_CHARGING || a->mode==RING_LOW_BATTERY) a->mode=RING_IDLE;
    if(a->mode==RING_FAULT || a->mode==RING_CHARGING || a->mode==RING_LOW_BATTERY) {
        a->consent=false; a->health_requested=false; a->manual_health=false; return;
    }
    if(!link_ok(a)) {
        a->consent=false;
        if(a->mode==RING_RECORDING || (a->mode==RING_MEASURING && a->manual_health)) a->mode=RING_IDLE;
        a->manual_health=false; a->health_requested=false;
    }
    if(a->mode==RING_RECORDING && !a->in.subscribed) a->mode=RING_IDLE;
    if(a->consent && (uint32_t)(now-a->consent_at)>=RING_CONSENT_MS) a->consent=false;
    if(a->mode==RING_RECORDING && (uint32_t)(now-a->mode_started)>=a->clip_ms) a->mode=RING_IDLE;
    if(a->mode==RING_MEASURING && ((!a->in.worn && !a->manual_health) || (uint32_t)(now-a->mode_started)>=RING_HEALTH_MS))  {a->mode=RING_IDLE;a->manual_health=false;}
    if(a->mode==RING_IDLE && (a->in.worn || a->manual_health) &&
       (a->health_requested || (uint32_t)(now-a->last_health)>=RING_HEALTH_INTERVAL_MS)) {
        a->mode=RING_MEASURING; a->mode_started=now; a->last_health=now;
        a->health_requested=false; a->consent=false;
    }
}
static void le16(uint8_t *o,uint16_t n) {o[0]=(uint8_t)n;o[1]=(uint8_t)(n>>8);}
void ring_status(const struct ring_app *a,uint8_t o[RING_STATUS_BYTES]) {
    memset(o,0,RING_STATUS_BYTES); o[0]=1; o[1]=(uint8_t)a->mode;
    o[2]=(uint8_t)((a->in.battery_valid?1:0)|(a->in.worn?2:0)|(a->in.encrypted?4:0)|(a->consent?8:0));
    le16(o+4,a->in.battery_valid?a->in.battery_mv:0);
    le16(o+6,a->clip_ms);
    for(unsigned i=0;i<4;++i) o[8+i]=(uint8_t)(a->clip_id>>(8*i));
}
