#include "media/nal_inventory.hpp"
#include <sstream>
namespace smartcut::media { namespace {
std::size_t prefix(std::span<const std::uint8_t> b,std::size_t i){if(i+3<=b.size()&&b[i]==0&&b[i+1]==0&&b[i+2]==1)return 3;if(i+4<=b.size()&&b[i]==0&&b[i+1]==0&&b[i+2]==0&&b[i+3]==1)return 4;return 0;}
unsigned type(Codec c,std::uint8_t h){return c==Codec::h264?h&31u:(h>>1u)&63u;}
bool ps(Codec c,unsigned t){return c==Codec::h264?(t==7||t==8):(t>=32&&t<=34);}
bool sei(Codec c,unsigned t){return c==Codec::h264?t==6:(t==39||t==40);}
bool ra(Codec c,unsigned t){return c==Codec::h264?t==5:(t>=16&&t<=23);}
}
NalInventory inventory_annex_b(Codec c,std::span<const std::uint8_t> b){NalInventory r{c,b.size(),{}};std::size_t cur=0;while(cur+3<=b.size()){while(cur+3<=b.size()&&!prefix(b,cur))++cur;if(cur+3>b.size())break;auto p=cur+prefix(b,cur);if(p>=b.size())break;std::size_t n=p+1;while(n+3<=b.size()&&!prefix(b,n))++n;auto e=n<b.size()?n:b.size();auto t=type(c,b[p]);r.units.push_back({p,e-p,t,ps(c,t),sei(c,t),ra(c,t),c==Codec::hevc&&t==62});cur=e;}return r;}
std::string to_json(const NalInventory& r){std::size_t ps_count=0,sei_count=0,ra_count=0,rpu_count=0;for(const auto&u:r.units){ps_count+=u.parameter_set;sei_count+=u.sei;ra_count+=u.random_access;rpu_count+=u.dolby_vision_rpu;}std::ostringstream o;o<<"{\"schema\":\"metadata-lab-report-v1\",\"codec\":\""<<(r.codec==Codec::h264?"h264":"hevc")<<"\",\"input_bytes\":"<<r.input_bytes<<",\"summary\":{\"nal_units\":"<<r.units.size()<<",\"parameter_sets\":"<<ps_count<<",\"sei_units\":"<<sei_count<<",\"random_access_units\":"<<ra_count<<",\"dolby_vision_rpu_units\":"<<rpu_count<<"},\"nal_units\":[";for(std::size_t i=0;i<r.units.size();++i){if(i)o<<',';auto&u=r.units[i];o<<"{\"offset\":"<<u.offset<<",\"size\":"<<u.size<<",\"type\":"<<u.type<<",\"parameter_set\":"<<(u.parameter_set?"true":"false")<<",\"sei\":"<<(u.sei?"true":"false")<<",\"random_access\":"<<(u.random_access?"true":"false")<<",\"dolby_vision_rpu\":"<<(u.dolby_vision_rpu?"true":"false")<<'}';}o<<"]}";return o.str();}
}
