#pragma once

#include <string>

#include "hardware/i2c.h"
#include "hardware/gpio.h"
#include "common/pimoroni_common.hpp"
#include "common/pimoroni_i2c.hpp"
#include "as7343_regs.hpp"

namespace pimoroni {

  class AS7343 {
    //--------------------------------------------------
    // Constants
    //--------------------------------------------------
  public:
    static const uint8_t DEFAULT_I2C_ADDRESS  = 0x39;

    //--------------------------------------------------
    // Enums
    //--------------------------------------------------
  public:
    enum class channel_count : uint8_t {
      SIX_CHANNEL      = 6,
      TWELVE_CHANNEL   = 12,
      EIGHTEEN_CHANNEL = 18
    };
/*
    enum class COMPENSATION_GAIN : float {
        F1 = 1.84f,
        F2 = 6.03f,
        FZ = 4.88f,
        F3 = 13.74f,
        F4 = 3.37f,
        FY = 2.82f,
        F5 = 6.72f,
        FXL = 2.22f,
        F6 = 3.17f,
        F7 = 1.95f,
        F8 = 12.25f,
        NIR = 1.00f,
    };
*/

    //--------------------------------------------------
    // Substructures
    //--------------------------------------------------
  public:
    struct reading {
        // Cycle 1
        uint16_t FZ = 0;   // 428-480 nm
        uint16_t FY = 0;   // 534-593 nm
        uint16_t FXL = 0;  // 593-628 nm
        uint16_t NIR = 0;  // 849-903 nm

        uint16_t c1_vis_tl = 0;  // Visible top-left
        uint16_t c1_vis_br = 0;  // Visible bottom-right
        uint16_t c1_astatus = 0; // (c1_astatus >> 8) & 0b10001111
                                 // 0b10000000 = saturated
                                 // 0b00001111 = gain lowest nibble

        // Cycle 2
        uint16_t F2 = 0;   // 408-448 nm
        uint16_t F3 = 0;   // 448-500 mn
        uint16_t F4 = 0;   // 500-534 nm
        uint16_t F6 = 0;   // 618-665 nm

        uint16_t c2_vis_tl = 0;
        uint16_t c2_vis_br = 0;
        uint16_t c2_astatus = 0;

        // Cycle 3
        uint16_t F1 = 0;   // 396-408 nm
        uint16_t F5 = 0;   // 531-594 nm
        uint16_t F7 = 0;   // 685-715 nm
        uint16_t F8 = 0;   // 715-766 nm

        uint16_t c3_vis_tl = 0;
        uint16_t c3_vis_br = 0;
        uint16_t c3_astatus = 0;
    };


    //--------------------------------------------------
    // Variables
    //--------------------------------------------------
  private:
    I2C *i2c;

    // interface pins with our standard defaults where appropriate
    int8_t address    = DEFAULT_I2C_ADDRESS;
    uint interrupt    = PIN_UNUSED;

    uint8_t read_cycles = 1;
    uint8_t ch_count = (uint8_t)channel_count::SIX_CHANNEL;


    //--------------------------------------------------
    // Constructors/Destructor
    //--------------------------------------------------
  public:
    AS7343(uint interrupt = PIN_UNUSED) : AS7343(new I2C(), interrupt) {};

    AS7343(I2C *i2c, uint interrupt = PIN_UNUSED) : i2c(i2c), interrupt(interrupt) {}


    //--------------------------------------------------
    // Methods
    //--------------------------------------------------
  public:
    bool init();
    void reset();

    // For print access in micropython
    i2c_inst_t* get_i2c() const;
    int get_sda() const;
    int get_scl() const;
    int get_int() const;

    void get_version(uint8_t &auxid, uint8_t &revid, uint8_t &hwid);

    reading read();

    void read_fifo(uint16_t *buf);

    void set_gain(float gain);
    void set_illumination_current(float current);
    void set_illumination_led(bool state);
    void set_measurement_time(float measurement_time_ms);
    void set_integration_time(float integration_time_us, uint8_t repeat=1);

    void set_channels(channel_count channel_count);

private:
    void bank_select(uint8_t bank=0);
  };

}
