#define ESP_NOW_HOST
// ===== 配置宏 =====
#ifndef ESP_NOW_DEFAULT_CHANNEL
#define ESP_NOW_DEFAULT_CHANNEL   6
#endif
#ifndef ESP_NOW_MAX_SLAVES
#define ESP_NOW_MAX_SLAVES        20
#endif
#ifndef ESP_NOW_CFG_INTERVAL
#define ESP_NOW_CFG_INTERVAL      500
#endif

// Flash Key
#define HOST_CFG_NS       "host_cfg"
#define HOST_CHANNEL_KEY  "channel"
#define SLAVES_NS         "slaves"
#define SLAVE_CFG_NS      "slave_cfg"
#define SLAVE_ID_KEY      "id"
#define SLAVE_HOST_KEY    "host"
#define SLAVE_CHANNEL_KEY "channel"

class EspNowPeer {
private:
  bool _initialized = false;
  bool _ready = false;
  uint8_t _myId;
  uint8_t _hostMac[6];
  uint8_t _currentChannel;
  
#ifdef ESP_NOW_HOST
  uint8_t _slaveMacs[ESP_NOW_MAX_SLAVES + 1][6];
  bool _slaveActive[ESP_NOW_MAX_SLAVES + 1];
  Preferences _prefs;
#endif

  char _recvBuf[256];
  bool _hasMsg = false;
  String _parsedValue;
  
  volatile bool _waitingReg = false;
  volatile uint8_t _waitingId = 0;
  volatile bool _regReceived = false;
  
  static bool _str2mac(const char* s, uint8_t* m) {
    return sscanf(s, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 
                  &m[0],&m[1],&m[2],&m[3],&m[4],&m[5]) == 6;
  }
  
  static void _mac2str(const uint8_t* m, char* s) {
    sprintf(s, "%02X:%02X:%02X:%02X:%02X:%02X", m[0],m[1],m[2],m[3],m[4],m[5]);
  }
  
  static void _onRecv(const uint8_t* mac, const uint8_t* data, int len) {
    if(_instance) _instance->_handleRecv(mac, data, len);
  }
  
  void _handleRecv(const uint8_t* mac, const uint8_t* data, int len) {
    if(len >= 256) return;
    memcpy(_recvBuf, data, len);
    _recvBuf[len] = '\0';
    _hasMsg = true;
    
#ifdef ESP_NOW_HOST
    if(_waitingReg && getMessageValue("climac")) {
      String val = lastValue();
      int dashPos = val.indexOf('-');
      if(dashPos > 0) {
        uint8_t recv_id = val.substring(0, dashPos).toInt();
        if(recv_id == _waitingId && recv_id >= 1 && recv_id <= ESP_NOW_MAX_SLAVES) {
          String macStr = val.substring(dashPos + 1);
          uint8_t recv_mac[6];
          if(_str2mac(macStr.c_str(), recv_mac)) {
            _regReceived = true;
            _registerSlave(recv_id, recv_mac);
          }
        }
      }
    }
#endif
  }
  
#ifdef ESP_NOW_HOST
  bool _saveChannel(uint8_t ch) {
    Preferences prefs;
    if(prefs.begin(HOST_CFG_NS, false)) {
      prefs.putUChar(HOST_CHANNEL_KEY, ch);
      prefs.end();
      return true;
    }
    return false;
  }
  
  uint8_t _loadChannel() {
    Preferences prefs;
    if(prefs.begin(HOST_CFG_NS, true)) {
      uint8_t ch = prefs.getUChar(HOST_CHANNEL_KEY, 0);
      prefs.end();
      if(ch >= 1 && ch <= 13) return ch;
    }
    return ESP_NOW_DEFAULT_CHANNEL;
  }
  
  bool _changeChannel(uint8_t newChannel) {
    if(newChannel < 1 || newChannel > 13) return false;
    if(newChannel == _currentChannel) return true;
    
    _saveChannel(newChannel);
    esp_wifi_set_channel(newChannel, WIFI_SECOND_CHAN_NONE);
    _currentChannel = newChannel;
    
    esp_now_deinit();
    delay(100);
    if(esp_now_init() != ESP_OK) return false;
    esp_now_register_recv_cb(_onRecv);
    return true;
  }
  
  bool _registerSlave(uint8_t id, uint8_t* mac) {
    if(id < 1 || id > ESP_NOW_MAX_SLAVES) return false;
    if(_slaveActive[id] && memcmp(_slaveMacs[id], mac, 6) == 0) return true;
    
    memcpy(_slaveMacs[id], mac, 6);
    _slaveActive[id] = true;
    
    _prefs.begin(SLAVES_NS, false);
    _prefs.putBytes((String("s")+String(id)).c_str(), mac, 6);
    _prefs.end();
    
    esp_now_peer_info_t p = {};
    memcpy(p.peer_addr, mac, 6);
    p.channel = _currentChannel;
    p.encrypt = false;
    esp_now_add_peer(&p);
    return true;
  }
  
  uint8_t* _findMac(uint8_t id) {
    if(id < 1 || id > ESP_NOW_MAX_SLAVES) return nullptr;
    return _slaveActive[id] ? _slaveMacs[id] : nullptr;
  }
  
  void _loadSlaves() {
    for(int i=0; i<=ESP_NOW_MAX_SLAVES; i++) _slaveActive[i] = false;
    _prefs.begin(SLAVES_NS, true);
    for(uint8_t id=1; id<=ESP_NOW_MAX_SLAVES; id++) {
      uint8_t mac[6];
      if(_prefs.getBytes((String("s")+String(id)).c_str(), mac, 6) == 6) {
        memcpy(_slaveMacs[id], mac, 6);
        _slaveActive[id] = true;
        esp_now_peer_info_t p = {};
        memcpy(p.peer_addr, mac, 6);
        p.channel = _currentChannel;
        p.encrypt = false;
        esp_now_add_peer(&p);
      }
    }
    _prefs.end();
  }
#endif

  bool _send(const uint8_t* mac, const char* key, const char* value) {
    if(!_ready || !mac || !key || !value) return false;
    char json[250];
    snprintf(json, sizeof(json), "{\"%s\":\"%s\"}", key, value);
    int len = strlen(json);
    if(len > 250) return false;
    return esp_now_send(mac, (uint8_t*)json, len) == ESP_OK;
  }
  
  static EspNowPeer* _instance;

public:
  EspNowPeer() { _instance = this; }
  
  bool begin(uint8_t myId = 0, const uint8_t* hostMac = nullptr) {
    if(_initialized) return true;
    _myId = myId;
    if(hostMac) memcpy(_hostMac, hostMac, 6);
    
#ifdef ESP_NOW_HOST
    _currentChannel = _loadChannel();
#else
    _currentChannel = _loadChannelSlave();
#endif
    
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    esp_wifi_set_channel(_currentChannel, WIFI_SECOND_CHAN_NONE);
    
    if(esp_now_init() != ESP_OK) return false;
    esp_now_register_recv_cb(_onRecv);
    
#ifdef ESP_NOW_HOST
    _prefs.begin(SLAVES_NS, false);
    _loadSlaves();
    _prefs.end();
#endif
    
    _initialized = true;
    _ready = true;
    return true;
  }
  
  // ===== 主机公开接口 =====
#ifdef ESP_NOW_HOST
  void setDevice(uint8_t slaveId, uint8_t channel = 0) {
    if(!_ready) return;
    if(channel == 0) channel = _currentChannel;
    if(channel != _currentChannel) _changeChannel(channel);
    
    uint8_t myMac[6];
    esp_read_mac(myMac, ESP_MAC_WIFI_STA);
    char hostMacStr[18];
    _mac2str(myMac, hostMacStr);
    
    _waitingReg = true;
    _waitingId = slaveId;
    _regReceived = false;
    
    uint32_t lastSend = 0;
    while(!_regReceived) {
      if(millis() - lastSend >= ESP_NOW_CFG_INTERVAL) {
        Serial1.printf("CFG:%d:%s:%dWZHY\n", slaveId, hostMacStr, channel);
        Serial.printf("CFG:%d:%s:%dWZHY\n", slaveId, hostMacStr, channel);
        lastSend = millis();
      }
      delay(10);
    }
    _waitingReg = false;
  }
  
  bool sendMessage(uint8_t slaveId, const String& key, const String& value) {
    if(!_ready) return false;
    uint8_t* mac = _findMac(slaveId);
    if(!mac) return false;
    return _send(mac, key.c_str(), value.c_str());
  }
  
  uint8_t getChannel() { return _currentChannel; }
#endif

  // ===== 从机公开接口 =====
#ifdef ESP_NOW_SLAVE
  uint8_t _loadChannelSlave() {
    Preferences prefs;
    if(prefs.begin(SLAVE_CFG_NS, true)) {
      uint8_t ch = prefs.getUChar(SLAVE_CHANNEL_KEY, 0);
      prefs.end();
      if(ch >= 1 && ch <= 13) return ch;
    }
    return ESP_NOW_DEFAULT_CHANNEL;
  }
  
  bool _saveChannelSlave(uint8_t ch) {
    Preferences prefs;
    if(prefs.begin(SLAVE_CFG_NS, false)) {
      prefs.putUChar(SLAVE_CHANNEL_KEY, ch);
      prefs.end();
      return true;
    }
    return false;
  }
  
  // ✅ 核心接口：解析并应用配置
  bool applyConfig(uint8_t id, const uint8_t* hostMac, uint8_t channel) {
    bool changed = false;
    
    // 信道变更
    if(channel != _currentChannel && channel >= 1 && channel <= 13) {
      _saveChannelSlave(channel);
      esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
      _currentChannel = channel;
      esp_now_deinit();
      delay(100);
      esp_now_init();
      esp_now_register_recv_cb(_onRecv);
      changed = true;
    }
    
    // ID 变更
    Preferences prefs;
    prefs.begin(SLAVE_CFG_NS, false);
    if(prefs.getUChar(SLAVE_ID_KEY, 0) != id) {
      prefs.putUChar(SLAVE_ID_KEY, id);
      _myId = id;
      changed = true;
    }
    
    // 主机 MAC 变更
    uint8_t storedHost[6];
    if(prefs.getBytes(SLAVE_HOST_KEY, storedHost, 6) != 6 || memcmp(storedHost, hostMac, 6) != 0) {
      prefs.putBytes(SLAVE_HOST_KEY, hostMac, 6);
      memcpy(_hostMac, hostMac, 6);
      changed = true;
    }
    prefs.end();
    
    // 发送 climac 确认
    _sendRegistration();
    return changed;
  }
  
  bool loadConfig() {
    Preferences prefs;
    prefs.begin(SLAVE_CFG_NS, true);
    _myId = prefs.getUChar(SLAVE_ID_KEY, 0);
    if(_myId == 0) { prefs.end(); return false; }
    if(prefs.getBytes(SLAVE_HOST_KEY, _hostMac, 6) != 6) { prefs.end(); return false; }
    prefs.end();
    return true;
  }
  
  bool _sendRegistration() {
    uint8_t myMac[6];
    esp_read_mac(myMac, ESP_MAC_WIFI_STA);
    char macStr[18];
    _mac2str(myMac, macStr);
    char content[40];
    snprintf(content, sizeof(content), "%d-%s", _myId, macStr);
    return _send(_hostMac, "climac", content);
  }
  
  bool sendMessage(const String& key, const String& value) {
    if(!_ready) return false;
    char content[220];
    snprintf(content, sizeof(content), "cli-%d-%s", _myId, value.c_str());
    return _send(_hostMac, key.c_str(), content);
  }
  
  uint8_t getChannel() { return _currentChannel; }
  uint8_t getMyId() { return _myId; }
#endif

  // ===== 通用接口 =====
  bool hasMessage() {
    bool has = _hasMsg;
    _hasMsg = false;
    return has;
  }
  
  bool getMessageValue(const String& key) {
    _parsedValue = "";
    if(strlen(_recvBuf) == 0) return false;
    String pattern = "\"" + key + "\":\"";
    int start = String(_recvBuf).indexOf(pattern);
    if(start == -1) return false;
    start += pattern.length();
    int end = String(_recvBuf).indexOf("\"", start);
    if(end == -1) return false;
    _parsedValue = String(_recvBuf).substring(start, end);
    return true;
  }
  
  String lastValue() { return _parsedValue; }
  void clearMessage() { _recvBuf[0] = '\0'; _parsedValue = ""; _hasMsg = false; }
  bool isReady() { return _ready; }
};

EspNowPeer* EspNowPeer::_instance = nullptr;

EspNowPeer peer;

void setup() {
  Serial.begin(115200);
  
  delay(1000);
  Serial1.begin(115200, SERIAL_8N1, 1, 2);//K10自身管脚不够利用串口接外部芯片扩展
  // ✅ 初始化主机（ID=255）
  peer.begin(255);
  
  Serial.printf("📡 主机就绪 信道=%d\n", peer.getChannel());
  
  // ===== 关键函数调用示例 =====
  
  // 示例 1：配置从机#5（使用当前信道）
  peer.setDevice(5);
  
  // 示例 2：配置从机#5 并切换到信道 6
  // peer.setDevice(5, 6);
  
  // 示例 3：发送消息到从机#5
  // peer.sendMessage(5, "c", "GO");
  
  // 示例 4：发送消息到从机#5（带参数）
  // peer.sendMessage(5, "set", "speed:100");
}

void loop() {
  // ✅ 接收从机消息
  if(peer.hasMessage()) {
    if(peer.getMessageValue("c")) {
      String val = peer.lastValue();
      // 解析 cli-<id>-<content> 格式
      if(val.startsWith("cli-")) {
        int d1 = val.indexOf('-', 4);
        if(d1 > 0) {
          String idStr = val.substring(4, d1);
          String content = val.substring(d1 + 1);
          Serial.printf("📥 从机#%s: %s\n", idStr.c_str(), content.c_str());
        }
      }
    }
  }
  
  // ✅ 实际使用时，根据业务逻辑调用：
  // peer.setDevice(5, 6);      // 配置从机
  peer.sendMessage(5, "c", "GO");  // 发送命令
  
  delay(100);
}