function results = evaluate_classification(yTrue, yPred, classLabels)
% EVALUATE_CLASSIFICATION  Compute OA, PA, UA, Kappa and confusion matrix
%
%   results = evaluate_classification(yTrue, yPred, classLabels)
%
%   yTrue, yPred   : true & predicted class labels
%   classLabels    : vector with all class IDs (optional)
%
%   results struct:
%       .confMat
%       .OA
%       .PA
%       .UA
%       .Kappa

    if nargin < 3
        classLabels = unique([yTrue; yPred]);
    end

    % Ensure column vectors
    yTrue = yTrue(:);
    yPred = yPred(:);

    % Build confusion matrix
    confMat = confusionmat(yTrue, yPred, 'Order', classLabels);

    % Overall Accuracy
    OA = trace(confMat) / sum(confMat(:));

    % Producer's & User's Accuracy (per class)
    PA = diag(confMat) ./ sum(confMat,2);  % Recall per class
    UA = diag(confMat) ./ sum(confMat,1)'; % Precision per class

    % Cohen's Kappa
    n = sum(confMat(:));
    po = OA;
    pe = sum(sum(confMat,1) .* sum(confMat,2)) / n^2;
    Kappa = (po - pe) / (1 - pe);

    % Pack results
    results.confMat = confMat;
    results.OA = OA;
    results.PA = PA;
    results.UA = UA;
    results.Kappa = Kappa;

    % Optional display
    fprintf('Overall Accuracy: %.2f%%\n', 100*OA);
    fprintf('Cohen''s Kappa   : %.3f\n', Kappa);
end
