#ifndef LAMP_OUTPUT_ADAPTER_H
#define LAMP_OUTPUT_ADAPTER_H

#include "lamp_guard.h"

#include <stdbool.h>
#include <stdint.h>

#define LG_OUTPUT_CHANNELS_PER_CHIP 24u
#define LG_OUTPUT_MAX_CHIPS ((LG_MAX_CHANNELS + LG_OUTPUT_CHANNELS_PER_CHIP - 1u) / LG_OUTPUT_CHANNELS_PER_CHIP)

typedef enum {
    LG_OUTPUT_OFF,
    LG_OUTPUT_PENDING,
    LG_OUTPUT_ON,
    LG_OUTPUT_LATCHED_FAULT
} lg_output_status;

/* Callbacks must be bounded. write_chip_pwm must write all 24 channel values
   atomically from the caller's perspective and return false on any I2C error. */
typedef struct {
    void *context;
    bool (*set_oe_n)(void *context, bool high);
    bool (*set_power_request)(void *context, bool enabled);
    bool (*write_chip_pwm)(void *context, uint8_t chip_index,
                           const uint8_t pwm[LG_OUTPUT_CHANNELS_PER_CHIP]);
    bool (*power_good)(void *context);
} lg_output_io;

typedef struct {
    lg_output_io io;
    uint32_t power_ready_timeout_ms;
    uint32_t power_wait_started_ms;
    uint64_t fault_session_id;
    uint64_t owner_session_id;
    uint16_t written_channels;
    uint8_t written_pwm[LG_MAX_CHANNELS];
    bool initialized;
    bool fault_latched;
    bool oe_n_high;
    bool power_requested;
    bool waiting_for_power;
    bool pwm_written;
    bool session_bound;
} lg_output;

/* Initialization immediately commands OE_N high and LED_PWR_REQ low. */
bool lg_output_init(lg_output *output, const lg_output_io *io,
                    uint32_t power_ready_timeout_ms);

/* Call serially after guard updates. A changed PWM image is blanked before
   all driver chips are updated. Power is requested only after every write
   succeeds; OE_N is released only after power_good is true. */
lg_output_status lg_output_sync(lg_output *output, const lg_guard *guard,
                                uint32_t now_ms);

/* Recovery requires a disarmed LG_OFF guard from a different session than
   the session that faulted, plus successful commands to both physical off
   controls. This prevents a user stop from clearing a hardware-output fault. */
bool lg_output_recover(lg_output *output, const lg_guard *guard);

#endif
