/*
  Copyright (c) 2025-2026 Kay Kasper
  under the MIT License (MIT)
*/

#ifndef PUSHBUTTON_TESTSWITCH
#define PUSHBUTTON_TESTSWITCH

#include "Common.h"
#include <SwitchExtensions.h>

void doPushButtonTests(int id){  // ID_PUSHBUTTONTEST = 3
  // maxDoubleMillis, minLongMillis, endLongByTime
  TestPushButtonDoubleLongAnalyzer TestPBDLAnalyzer(10, 20, true);
  TestSwitch stdSwitch(&TestPBDLAnalyzer, true, INPUT_PIN, 0, true);
  unsigned long tmpMicros, startmicro = 0;
  int seq;
  boolean tmpBool;

  stdSwitch.setMapping(PBDL_STATE_E_OFF, 10);
  stdSwitch.setMapping(PBDL_STATE_E_SINGLE, 11);
  stdSwitch.setMapping(PBDL_STATE_E_DOUBLE, 12);
  stdSwitch.setMapping(PBDL_STATE_E_LONG, 13);

  seq = 0; // no waits, negative logic
  stdSwitch.setReadCycleMillis(0);
  stdSwitch.setDebounceMillis(0);
  stdSwitch.setInvertRaw(true);
  stdSwitch.reset();
  check(stdSwitch.getState(),SW_STATE_UNDEFINED,id,seq+1);
  check(stdSwitch.getPrevState(),SW_STATE_UNDEFINED,id,seq+2);
  check(stdSwitch.getMappedState(),SW_STATE_UNDEFINED,id,seq+3);
  check(stdSwitch.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+4);

  seq = 10; // 1. change -> state OFF
  stdSwitch.setRawState(1); // invertRaw -> 0
  check(stdSwitch.getState(),SW_STATE_UNDEFINED,id,seq+1);
  check(stdSwitch.hasChanged(),true,id,seq+2);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+3);
  check(stdSwitch.getPrevState(),SW_STATE_UNDEFINED,id,seq+4);
  check(stdSwitch.hasChanged(),false,id,seq+5);
  check(stdSwitch.getMappedState(),10,id,seq+6);
  check(stdSwitch.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+7);

  seq = 20; // 2. change -> start single push 
  stdSwitch.setRawState(0); // invertRaw -> 1
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+1);
  check(stdSwitch.hasChanged(),false,id,seq+2);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+3);
  check(stdSwitch.getPrevState(),SW_STATE_UNDEFINED,id,seq+4);
  check(stdSwitch.hasChanged(),false,id,seq+5);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+8);
  check(stdSwitch.getMappedState(),10,id,seq+6);
  check(stdSwitch.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+7);

  seq = 30; // 3. change -> end single push 
  stdSwitch.setRawState(1); // invertRaw -> 0
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+5);
  delay(11); // wait longer than  double push timeout, but less than long push
  check(stdSwitch.hasChanged(),true,id,seq+6);  //SINGLE
  check(stdSwitch.getState(),PBDL_STATE_E_SINGLE,id,seq+7);
  check(stdSwitch.getPrevState(),PBDL_STATE_E_OFF,id,seq+8);
  check(stdSwitch.getMappedState(),11,id,seq+10);
  check(stdSwitch.getPrevMappedState(),10,id,seq+11);

  seq = 40; // 4. change -> off 
  check(stdSwitch.hasChanged(),true,id,seq+1);  // OFF
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+2);
  check(stdSwitch.getPrevState(),PBDL_STATE_E_SINGLE,id,seq+3);
  check(stdSwitch.getMappedState(),10,id,seq+4);
  check(stdSwitch.getPrevMappedState(),11,id,seq+5);

  stdSwitch.setReadCycleMillis(0);
  stdSwitch.setDebounceMillis(0);
  stdSwitch.setInvertRaw(false); // switch to positive logic
  stdSwitch.reset();

  seq = 50; // 1. change 
  check(stdSwitch.getState(),SW_STATE_UNDEFINED,id,seq+1);
  check(stdSwitch.getPrevState(),SW_STATE_UNDEFINED,id,seq+2);
  check(stdSwitch.getMappedState(),SW_STATE_UNDEFINED,id,seq+3);
  check(stdSwitch.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+4);
  stdSwitch.setRawState(0); 
  check(stdSwitch.hasChanged(),true,id,seq+5);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+6);
  check(stdSwitch.getPrevState(),SW_STATE_UNDEFINED,id,seq+7);
  check(stdSwitch.getMappedState(),10,id,seq+8);
  check(stdSwitch.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+9);

  seq = 60; // 2. change -> start double push 
  stdSwitch.setRawState(1); 
  check(stdSwitch.hasChanged(),false,id,seq+1);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+2);
  check(stdSwitch.getPrevState(),SW_STATE_UNDEFINED,id,seq+3);
  check(stdSwitch.getMappedState(),10,id,seq+4);
  check(stdSwitch.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+5);

  seq = 65; // 3. change -> end 1. push 
  stdSwitch.setRawState(0); 
  check(stdSwitch.hasChanged(),false,id,seq+1);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+2);
  check(stdSwitch.getPrevState(),SW_STATE_UNDEFINED,id,seq+3);
  check(stdSwitch.getMappedState(),10,id,seq+4);
  check(stdSwitch.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+5);

  seq = 70; // 4. change -> start 2. push 
  stdSwitch.setRawState(1); 
  check(stdSwitch.hasChanged(),false,id,seq+1);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+2);
  check(stdSwitch.getPrevState(),SW_STATE_UNDEFINED,id,seq+3);
  check(stdSwitch.getMappedState(),10,id,seq+4);
  check(stdSwitch.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+5);

  seq = 75; // 5. change -> end 2. push 
  stdSwitch.setRawState(0); 
  check(stdSwitch.hasChanged(),true,id,seq+1);
  check(stdSwitch.getState(),PBDL_STATE_E_DOUBLE,id,seq+2);
  check(stdSwitch.getPrevState(),PBDL_STATE_E_OFF,id,seq+3);
  check(stdSwitch.getMappedState(),12,id,seq+4);
  check(stdSwitch.getPrevMappedState(),10,id,seq+5);

  seq = 80; // 6. change -> off + start long push 
  stdSwitch.setRawState(1); 
  check(stdSwitch.hasChanged(),true,id,seq+1);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+2);
  check(stdSwitch.getPrevState(),PBDL_STATE_E_DOUBLE,id,seq+3);
  check(stdSwitch.getMappedState(),10,id,seq+4);
  check(stdSwitch.getPrevMappedState(),12,id,seq+5);

  seq = 85; // 7. change -> end long push based on timeout
  delay(18);
  check(stdSwitch.hasChanged(),false,id,seq+1);
  delay(4);
  check(stdSwitch.hasChanged(),true,id,seq+2);
  check(stdSwitch.getState(),PBDL_STATE_E_LONG,id,seq+3);
  check(stdSwitch.getPrevState(),PBDL_STATE_E_OFF,id,seq+4);
  check(stdSwitch.hasChanged(),true,id,seq+5);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+6);
  check(stdSwitch.getPrevState(),PBDL_STATE_E_LONG,id,seq+7);

  stdSwitch.setRawState(0); 
  check(stdSwitch.hasChanged(),false,id,seq+8);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+9);

  TestPBDLAnalyzer.setEndLongByTime(false);

  seq = 100; // new test of long pushes without timeout, start long push 
  stdSwitch.setRawState(1); 
  check(stdSwitch.hasChanged(),false,id,seq+1);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+2);
  check(stdSwitch.getPrevState(),PBDL_STATE_E_LONG,id,seq+3);
  delay(5);
  check(stdSwitch.hasChanged(),false,id,seq+4);
  delay(5);
  check(stdSwitch.hasChanged(),false,id,seq+5);
  delay(5);
  check(stdSwitch.hasChanged(),false,id,seq+6);
  delay(5);
  check(stdSwitch.hasChanged(),false,id,seq+7);
  delay(10);
  stdSwitch.setRawState(0);
  check(stdSwitch.hasChanged(),true,id,seq+8);
  check(stdSwitch.getState(),PBDL_STATE_E_LONG,id,seq+9);
  check(stdSwitch.getPrevState(),PBDL_STATE_E_OFF,id,seq+10);
  check(stdSwitch.hasChanged(),true,id,seq+10);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+12);
  check(stdSwitch.getPrevState(),PBDL_STATE_E_LONG,id,seq+13);
  check(stdSwitch.hasChanged(),false,id,seq+14);
  check(stdSwitch.getState(),PBDL_STATE_E_OFF,id,seq+15);

  // performance

  Serial.println("\nPerformance PushButtonDoubleLong:");

  Serial.print("1000 * hasChanged() true: ");

  stdSwitch.setInvertRaw(false);
  stdSwitch.setReadCycleMillis(0);
  stdSwitch.setDebounceMillis(0);
  stdSwitch.reset();

  startmicro = micros();
  for(int i = 0 ; i < 1000 ; i++){
    stdSwitch.setRawState(i & 0x0001);
    tmpBool = stdSwitch.hasChanged();
  }
  Serial.print(micros() - startmicro);
  Serial.println(" micros");

  Serial.print("1000 * hasChanged() false: ");

  stdSwitch.setInvertRaw(false);
  stdSwitch.setReadCycleMillis(0);
  stdSwitch.setDebounceMillis(0);
  stdSwitch.reset();

  startmicro = micros();
  stdSwitch.setRawState(0);
  stdSwitch.hasChanged();
  for(int i = 0 ; i < 1000 ; i++){
    stdSwitch.setRawState(0);
    tmpBool = stdSwitch.hasChanged();
  }
  Serial.print(micros() - startmicro);
  Serial.println(" micros");
}

#endif
