#ifndef IS31FL3236A_H
#define IS31FL3236A_H

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

#define IS31FL3236A_CHANNELS 36u
#define IS31FL3236A_MAX_TRANSACTION_BYTES (IS31FL3236A_CHANNELS + 1u)
#define IS31FL3236A_MAX_GROUP_CHIPS 4u

typedef enum {
    IS31FL3236A_PWM_3KHZ = 0u,
    IS31FL3236A_PWM_22KHZ = 1u
} is31fl3236a_pwm_frequency;

typedef bool (*is31fl3236a_i2c_write_fn)(void *context, uint8_t address_7bit,
                                         const uint8_t *bytes, size_t length);
typedef bool (*is31fl3236a_pin_read_fn)(void *context);
typedef bool (*is31fl3236a_pin_write_fn)(void *context, bool asserted);

/* All safety callbacks must use bounded operations and read/write physical pins. */
typedef struct {
    void *context;
    is31fl3236a_i2c_write_fn write_transaction;
    is31fl3236a_pin_read_fn sdb_is_low;
    is31fl3236a_pin_read_fn driver_supply_is_valid;
    is31fl3236a_pin_read_fn output_permit_is_active;
    is31fl3236a_pin_write_fn set_sdb_low;
    is31fl3236a_pin_write_fn force_outputs_off;
} is31fl3236a_io;

typedef struct {
    is31fl3236a_io io;
    uint8_t address_7bit;
    is31fl3236a_pwm_frequency pwm_frequency;
    bool initialized;
    bool frame_loaded;
    bool outputs_enabled;
    bool fault_latched;
} is31fl3236a_driver;

/* AD straps map GND/SCL/SDA/VCC to 0x3C/0x3D/0x3E/0x3F. */
uint8_t is31fl3236a_address_from_ad(uint8_t ad_code);

/*
 * Initialize only after VCC is valid and physical SDB is held low. The function
 * clears both channel banks, selects the requested PWM frequency, and leaves
 * software shutdown active. It never releases SDB or enables the LED output.
 */
bool is31fl3236a_initialize(is31fl3236a_driver *driver,
                            const is31fl3236a_io *io,
                            uint8_t address_7bit,
                            is31fl3236a_pwm_frequency pwm_frequency);

/*
 * Stage and latch all 36 PWM and channel-control values while SDB is low.
 * channel_control accepts only SL[1:0] and OUT bits (mask 0x07). The caller
 * must hold the output off across this operation and explicitly re-enable it.
 */
bool is31fl3236a_write_frame(is31fl3236a_driver *driver,
                             const uint8_t pwm[IS31FL3236A_CHANNELS],
                             const uint8_t channel_control[IS31FL3236A_CHANNELS]);

/* Enable only with a loaded frame, valid driver supply and active system permit. */
bool is31fl3236a_enable_outputs(is31fl3236a_driver *driver);

/* Assert hardware SDB first; register shutdown writes are best-effort afterward. */
bool is31fl3236a_disable_outputs(is31fl3236a_driver *driver);

/*
 * Shared-SDB group operations for 61/122-channel lamp candidates. Every chip
 * must share the same physical I/O context and unique I2C address. Enable
 * writes all chips while common SDB remains low, rechecks supply/permit, then
 * releases SDB once so no partially enabled chip is exposed. Disable asserts
 * common SDB once before best-effort software shutdown writes.
 */
bool is31fl3236a_enable_group(is31fl3236a_driver *drivers, size_t driver_count);
bool is31fl3236a_disable_group(is31fl3236a_driver *drivers, size_t driver_count);
bool is31fl3236a_stage_group_frame(
    is31fl3236a_driver *drivers, size_t driver_count,
    const uint8_t pwm[][IS31FL3236A_CHANNELS],
    const uint8_t channel_control[][IS31FL3236A_CHANNELS]);
bool is31fl3236a_update_group(
    is31fl3236a_driver *drivers, size_t driver_count,
    const uint8_t pwm[][IS31FL3236A_CHANNELS],
    const uint8_t channel_control[][IS31FL3236A_CHANNELS]);

bool is31fl3236a_is_ready(const is31fl3236a_driver *driver);

#endif
