function [winLen_rec,nfft_rec,info] = recommend_winlen_nfft(t,rpm,varargin)
% recommend_winlen_nfft
%
% Recommends window length (winLen) and FFT length (nfft) for
% order tracking based on signal characteristics.
%
% INPUTS
%   t    : time vector (s)
%   rpm  : rotational speed (RPM)
%
% OPTIONAL NAME-VALUE PAIRS
%   'MaxRPMChangeFrac' : max allowed fractional RPM change per window (default 0.10)
%   'WinLenBounds'     : [min max] samples (default [512 4096])
%   'NFFTMin'          : minimum nfft (default 4096)
%
% OUTPUTS
%   winLen_rec : recommended window length (samples, power of 2)
%   nfft_rec   : recommended FFT length (power of 2)
%   info       : struct with diagnostic metrics (for GUI display)

%% ---------------- Input handling ----------------
p = inputParser;
p.addParameter('MaxRPMChangeFrac',0.10,@(x)x>0 && x<1);
p.addParameter('WinLenBounds',[512 4096],@(x)isnumeric(x)&&numel(x)==2);
p.addParameter('NFFTMin',4096,@(x)x>=256);
p.parse(varargin{:});

maxFrac = p.Results.MaxRPMChangeFrac;
winBnd  = p.Results.WinLenBounds;
nfftMin = p.Results.NFFTMin;

t   = t(:);
rpm = rpm(:);

%% ---------------- Basic metrics -----------------
dt = mean(diff(t));
fs = 1/dt;

rpm_safe = max(rpm,1e-3);
shaft_hz = rpm_safe/60;

% Fractional RPM rate (|dRPM/dt| / RPM)
drpm_dt = gradient(rpm_safe,dt);
fracRate = abs(drpm_dt)./rpm_safe;

maxFracRate = max(fracRate(~isnan(fracRate) & ~isinf(fracRate)));

%% ---------------- Window length recommendation ---
% Want RPM to change less than maxFrac over window
Twindow_max = maxFrac / maxFracRate;

% Convert to samples
winLen_est = Twindow_max * fs;

% Snap to power of 2
winLen_pow = 2^round(log2(winLen_est));

% Enforce bounds
winLen_rec = min(max(winLen_pow,winBnd(1)),winBnd(2));

%% ---------------- FFT length recommendation ------
nfft_rec = max(nfftMin,2^nextpow2(winLen_rec));

%% ---------------- Diagnostic info ----------------
info.fs              = fs;
info.dt              = dt;
info.rpm_min         = min(rpm_safe);
info.rpm_max         = max(rpm_safe);
info.maxFracRate     = maxFracRate;
info.window_time_s   = winLen_rec/fs;
info.freq_resolution = fs/winLen_rec;
info.freq_spacing    = fs/nfft_rec;

%% ---------------- Safety fallback ----------------
if isnan(winLen_rec) || isinf(winLen_rec)
    winLen_rec = 1024;
    nfft_rec   = max(nfftMin,4096);
end

end
