#pragma once
#include "face_utils.hpp"

#include <iostream>

// ── FaceAlignerFunc ───────────────────────────────────────────────────────────
// KPN node: applies a 5-point similarity transform to each detected face,
// producing a 112×112 BGR crop suitable for ArcFace inference.
//
// Alignment uses cv::estimateAffinePartial2D (RANSAC) to fit the detected
// landmarks to ArcFace canonical positions.  Degenerate detections (where the
// affine fit fails) are silently dropped from the output vectors.

struct FaceAlignerFunc {
    static constexpr std::string_view label() { return "face_aligner"; }

    AlignedSceneFrame operator()(SceneFrame sf) {
        if (sf.source.eof || sf.faces.empty())
            return {std::move(sf.source), {}, {}};

        std::vector<DetectedFace> good_faces;
        std::vector<cv::Mat>      crops;
        good_faces.reserve(sf.faces.size());
        crops.reserve(sf.faces.size());

        for (auto& face : sf.faces) {
            // The AR-030 misfit comes from the transform the warp already needs,
            // so visibility costs no extra fit.
            float residual = -1.f;
            cv::Mat crop = align_face(sf.source.image, face.landmarks, &residual);
            if (crop.empty()) {
                std::cerr << "[face_aligner] degenerate detection skipped\n";
                continue;
            }
            face.alignment_residual = residual;
            good_faces.push_back(face);
            crops.push_back(std::move(crop));
        }

        return {std::move(sf.source), std::move(good_faces), std::move(crops)};
    }

};
