function plot_results2(results, cfg, classLabels)
% PLOT_RESULTS2 — Scenario 2 plotting suite
% Produces and saves:
%   (A) CV heatmap of Kappa over (#features × radius)
%   (B) CV heatmap of mean #rules over the same grid
%   (C) Confusion matrix on TEST for the best model
%   (D) PA/UA bars on TEST
%   (E) Learning curves (train/validation error)
%   (F) MFs before/after for the best model
%   (G) Truth vs Prediction (TEST)
%   (H) ReliefF feature weights bar chart
%
% All PNGs saved under cfg.outDir.

outDir = cfg.outDir;

% (A) CV heatmap — Kappa
fig = figure('Color','w');
imagesc(results.cvScores);
set(gca,'XTick',1:numel(results.rGrid),'XTickLabel',compose('%.2f',results.rGrid));
set(gca,'YTick',1:numel(results.fGrid),'YTickLabel',string(results.fGrid));
xlabel('SC radius r_a'); ylabel('#Features (ReliefF)'); colorbar;
title(sprintf('CV mean Kappa (K=%d folds)', cfg.kfold));
for i = 1:numel(results.fGrid)
    for j = 1:numel(results.rGrid)
        text(j,i,sprintf('%.2f',results.cvScores(i,j)),...
            'HorizontalAlignment','center','Color','w','FontWeight','bold');
    end
end
exportgraphics(fig, fullfile(outDir,'cv_kappa_heatmap.png'), 'Resolution', 200);
close(fig);

% (B) CV heatmap — mean #rules
fig = figure('Color','w');
imagesc(results.cvRules);
set(gca,'XTick',1:numel(results.rGrid),'XTickLabel',compose('%.2f',results.rGrid));
set(gca,'YTick',1:numel(results.fGrid),'YTickLabel',string(results.fGrid));
xlabel('SC radius r_a'); ylabel('#Features (ReliefF)'); colorbar;
title(sprintf('CV mean #Rules (K=%d folds)', cfg.kfold));
for i = 1:numel(results.fGrid)
    for j = 1:numel(results.rGrid)
        text(j,i,sprintf('%d',results.cvRules(i,j)),...
            'HorizontalAlignment','center','Color','w','FontWeight','bold');
    end
end
exportgraphics(fig, fullfile(outDir,'cv_rules_heatmap.png'), 'Resolution', 200);
close(fig);

% (C) Confusion matrix — TEST
fig = figure('Color','w');
confusionchart(results.metrics.confMat, string(classLabels), ...
    'Title', sprintf('Confusion — best model (features=%d, r=%.2f, rules=%d)', ...
    results.bestF, results.bestR, numel(results.bestFis.rule)));
exportgraphics(fig, fullfile(outDir,'cm_best_model.png'), 'Resolution', 200);
close(fig);

% (D) PA/UA bars — TEST
fig = figure('Color','w');
t = tiledlayout(2,1,'TileSpacing','compact','Padding','compact');
nexttile; bar(results.metrics.PA); ylim([0 1]);
xticks(1:numel(classLabels)); xticklabels(string(classLabels));
ylabel('PA (Recall)'); title('Producer''s Accuracy (TEST)'); grid on;
nexttile; bar(results.metrics.UA); ylim([0 1]);
xticks(1:numel(classLabels)); xticklabels(string(classLabels));
ylabel('UA (Precision)'); title('User''s Accuracy (TEST)'); grid on;
exportgraphics(fig, fullfile(outDir,'pa_ua_best_model.png'), 'Resolution', 200);
close(fig);

% (E) Learning curves
fig = figure('Color','w');
plot(1:numel(results.trError), results.trError, 'LineWidth', 1.2); hold on;
if ~isempty(results.vaError)
    plot(1:numel(results.vaError), results.vaError, '--', 'LineWidth', 1.2);
    legend('Training Error','Validation Error','Location','best');
else
    legend('Training Error','Location','best');
end
xlabel('Epoch'); ylabel('Error'); grid on;
title(sprintf('Learning Curve — best model (features=%d, r=%.2f)', ...
    results.bestF, results.bestR));
exportgraphics(fig, fullfile(outDir,'learning_best_model.png'), 'Resolution', 200);
close(fig);

% (F) MFs before/after for the best model
try
    plot_mfs_before_after(results.initFis, results.bestFis, ...
        sprintf('MFs — best model (features=%d, r=%.2f)', results.bestF, results.bestR), ...
        fullfile(outDir,'mfs_best_model.png'));
catch ME
    warning('MF plot failed: %s', ME.message);
end

% (G) Truth vs Prediction — TEST
fig = figure('Color','w');
plot(results.ytrue, 'LineWidth', 1.0); hold on;
plot(results.yhat,  '--', 'LineWidth', 1.0);
xlabel('Test sample index'); ylabel('Class label'); grid on;
title('Truth vs Prediction (TEST)');
legend('Truth','Prediction','Location','best');
exportgraphics(fig, fullfile(outDir,'pred_vs_truth_best_model.png'), 'Resolution', 200);
close(fig);

% (H) ReliefF feature weights (on full train+val)
fig = figure('Color','w');
w   = results.reliefW(:);
idx = results.selIdx(:);
% map back: selected indices first for clarity
bar(1:numel(idx), w(idx)); grid on;
xlabel('Selected feature index'); ylabel('ReliefF weight');
title(sprintf('ReliefF weights (top %d features)', results.bestF));
exportgraphics(fig, fullfile(outDir,'relieff_weights_selected.png'), 'Resolution', 200);
close(fig);




% ===================== local helper =====================
function plot_mfs_before_after(fisBefore, fisAfter, suptitleStr, outPng)
    D = numel(fisAfter.Inputs);
    fig = figure('Color','w','Position',[100 100 1200 420]);
    t = tiledlayout(2, D, 'TileSpacing','compact','Padding','compact');
    for d = 1:D
        nexttile(d); hold on;
        try
            [xB, yB] = plotmf(fisBefore, 'input', d);
            plot(xB, yB, 'LineWidth', 1.0);
        catch
        end
        title(sprintf('Input %d — BEFORE', d));
        ylim([0 1]); grid on;

        nexttile(D + d); hold on;
        [xA, yA] = plotmf(fisAfter, 'input', d);
        plot(xA, yA, 'LineWidth', 1.0);
        title(sprintf('Input %d — AFTER', d));
        ylim([0 1]); grid on;
    end
    sgtitle(suptitleStr);
    exportgraphics(fig, outPng, 'Resolution', 200);
    close(fig);
end
end
