#include "lamp_measurement.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
static void unchanged(const lamp_adc_frame *f,uint16_t cal,uint32_t now,enum lamp_measurement_status expected) {
 lamp_measurement m,old;memset(&m,0xa5,sizeof m);old=m;
 assert(lamp_measurement_from_frame(f,cal,now,&m)==expected);
 assert(memcmp(&old,&m,sizeof m)==0);
}
int main(void) {
 unsigned cases=0;
 const unsigned cals[]={1500,1638,1800},voltages[]={2800,3000,3500};
 for(unsigned ci=0;ci<3;ci++)for(unsigned vi=0;vi<3;vi++){
  unsigned cal=cals[ci],ref=(3000u*cal+voltages[vi]/2u)/voltages[vi];
  for(unsigned code=0;code<4095;code++){
   lamp_adc_frame f={(uint16_t)code,(uint16_t)code,(uint16_t)code,(uint16_t)ref,UINT32_MAX-10u,UINT32_MAX-1u,1u};
   lamp_measurement m;assert(lamp_measurement_from_frame(&f,(uint16_t)cal,5,&m)==LAMP_MEAS_OK);
   /* Independent floating-point physical equations, not helper implementation. */
   double vdda=3.0*(double)cal/ref,vpin=vdda*code/4095.;
   assert(fabs(m.estimated_vdda_uv-vdda*1e6)<=0.50001);
   assert(fabs(m.nominal_led_uv-vpin*2*1e6)<=0.50001);
   assert(fabs(m.nominal_led_current_ua-vpin/(0.01*20)*1e6)<=0.50001);
   assert(((m.quality_flags&LAMP_MEAS_CURRENT_OUTSIDE_GAIN_WINDOW)!=0)==(vpin<0.5 || vpin>vdda-0.5));
   if(code<=16)assert((m.quality_flags&LAMP_MEAS_NTC_NEAR_SHORT)!=0 && m.nominal_ntc_ohm==0);
   else if(code>=4079)assert((m.quality_flags&LAMP_MEAS_NTC_NEAR_OPEN)!=0 && m.nominal_ntc_ohm==0);
   else assert(fabs(m.nominal_ntc_ohm-(10000.*code/(4095-code)))<=0.50001);
   assert(m.sequence==1 && m.first_sample_ms==f.first_sample_ms && m.completed_ms==f.completed_ms);
   ++cases;
  }
 }
 lamp_adc_frame f={2048,2048,1000,1489,100,110,1};
 unchanged(NULL,1638,110,LAMP_MEAS_ARGUMENT);
 assert(lamp_measurement_from_frame(&f,1638,110,NULL)==LAMP_MEAS_ARGUMENT);
 for(unsigned cal=0;cal<65536;cal++)if(cal<1000 || cal>2000)unchanged(&f,(uint16_t)cal,110,LAMP_MEAS_CALIBRATION);
 const unsigned badraw[]={4095,4096,65535};
 for(unsigned i=0;i<3;i++){
  lamp_adc_frame b=f;b.led_v_raw=badraw[i];unchanged(&b,1638,110,LAMP_MEAS_RAW_RANGE);
  b=f;b.led_i_raw=badraw[i];unchanged(&b,1638,110,LAMP_MEAS_RAW_RANGE);
  b=f;b.vrefint_raw=badraw[i];unchanged(&b,1638,110,LAMP_MEAS_RAW_RANGE);
 }
 lamp_adc_frame b=f;b.ntc_raw=65535;unchanged(&b,1638,110,LAMP_MEAS_RAW_RANGE);
 b=f;b.vrefint_raw=0;unchanged(&b,1638,110,LAMP_MEAS_RAW_RANGE);
 b=f;b.vrefint_raw=400;unchanged(&b,1638,110,LAMP_MEAS_SUPPLY_RANGE);
 b=f;b.vrefint_raw=3000;unchanged(&b,1638,110,LAMP_MEAS_SUPPLY_RANGE);
 unchanged(&f,1638,121,LAMP_MEAS_STALE);unchanged(&f,1638,109,LAMP_MEAS_STALE);
 b=f;b.completed_ms=121;unchanged(&b,1638,121,LAMP_MEAS_STALE);
 b=f;b.sequence=0;unchanged(&b,1638,110,LAMP_MEAS_STALE);
 /* A frame at20ms age is usable,21ms is not. Completion need not be simultaneous. */
 lamp_measurement m;assert(lamp_measurement_from_frame(&f,1638,120,&m)==LAMP_MEAS_OK);
 printf("PASS: %u complete12bit-code nominal voltage/current/NTC oracle cases; all out-of-credibility calibration words; rail clipping, raw range, supply bounds, stale/partial timestamp and wrap checks; failed calls preserve output. Diagnostic math only.\n",cases);
 return 0;
}
