<?php

namespace App\Modules\Face\Controllers;

use App\Core\BaseApiController;
use App\Modules\Academic\Models\StudentModel;
use App\Modules\Face\Models\StudentFaceModel;
use App\Modules\Face\Services\FaceService;
use CodeIgniter\HTTP\ResponseInterface;

class FaceController extends BaseApiController
{
    /**
     * POST /api/face/import-formal
     * Body: {
     *   "items": [
     *     { "student_id": 123, "url": "https://..." },
     *     ...
     *   ]
     * }
     *
     * Admin-only (protected by filter admin_only).
     */
    public function importFormal(): ResponseInterface
    {
        $payload = $this->request->getJSON(true) ?? [];
        $items   = $payload['items'] ?? [];

        if (! is_array($items) || $items === []) {
            return $this->errorResponse('items wajib berupa array', null, null, ResponseInterface::HTTP_UNPROCESSABLE_ENTITY);
        }

        $studentModel = new StudentModel();
        $faceModel    = new StudentFaceModel();
        $faceService  = new FaceService();

        $success = 0;
        $fail    = 0;
        $errors  = [];

        foreach ($items as $item) {
            $studentId = (int) ($item['student_id'] ?? 0);
            $url       = trim((string) ($item['url'] ?? ''));

            if ($studentId < 1 || $url === '') {
                $fail++;
                $errors[] = [
                    'student_id' => $studentId,
                    'url'        => $url,
                    'reason'     => 'student_id dan url wajib diisi',
                ];
                continue;
            }

            $student = $studentModel->find($studentId);
            if (! $student) {
                $fail++;
                $errors[] = [
                    'student_id' => $studentId,
                    'url'        => $url,
                    'reason'     => 'Siswa tidak ditemukan',
                ];
                continue;
            }

            $tmpFile = tempnam(sys_get_temp_dir(), 'face_');
            try {
                $imgData = @file_get_contents($url);
                if ($imgData === false) {
                    throw new \RuntimeException('Gagal mengunduh gambar dari URL');
                }
                file_put_contents($tmpFile, $imgData);

                $result = $faceService->extractEmbeddingWithQuality($tmpFile);

                $faceModel->insert([
                    'student_id'    => $studentId,
                    'embedding'     => json_encode($result['embedding']),
                    'source'        => 'formal',
                    'quality_score' => $result['quality_score'],
                ]);

                // Simpan URL formal di tabel students
                $studentModel->update($studentId, ['photo_formal_url' => $url]);

                $success++;
            } catch (\Throwable $e) {
                $fail++;
                $errors[] = [
                    'student_id' => $studentId,
                    'url'        => $url,
                    'reason'     => $e->getMessage(),
                ];
            } finally {
                if (is_file($tmpFile)) {
                    @unlink($tmpFile);
                }
            }
        }

        return $this->successResponse([
            'success_count' => $success,
            'fail_count'    => $fail,
            'errors'        => $errors,
        ], 'Import foto formal selesai');
    }

    /**
     * POST /api/face/enroll-live
     * Body: {
     *   "student_id": 123,
     *   "images": ["data:image/jpeg;base64,...", "..."]
     * }
     *
     * Dipanggil saat aktivasi dari device (3–5 frame).
     */
    public function enrollLive(): ResponseInterface
    {
        $payload   = $this->request->getJSON(true) ?? [];
        $studentId = (int) ($payload['student_id'] ?? 0);
        $images    = $payload['images'] ?? [];

        if ($studentId < 1) {
            return $this->errorResponse('student_id wajib diisi', null, null, ResponseInterface::HTTP_UNPROCESSABLE_ENTITY);
        }

        if (! is_array($images) || count($images) < 1) {
            return $this->errorResponse('images wajib berisi minimal 1 item', null, null, ResponseInterface::HTTP_UNPROCESSABLE_ENTITY);
        }

        $studentModel = new StudentModel();
        $student      = $studentModel->find($studentId);
        if (! $student) {
            return $this->errorResponse('Siswa tidak ditemukan', null, null, ResponseInterface::HTTP_NOT_FOUND);
        }

        $faceModel   = new StudentFaceModel();
        $faceService = new FaceService();

        $embeddings = [];
        $saved      = 0;
        $errors     = [];

        foreach ($images as $idx => $imgData) {
            $tmpFile = tempnam(sys_get_temp_dir(), 'live_');
            try {
                $raw = $this->decodeBase64Image($imgData);
                if ($raw === null) {
                    throw new \RuntimeException('Format gambar tidak valid (harus base64)');
                }
                file_put_contents($tmpFile, $raw);

                $result = $faceService->extractEmbeddingWithQuality($tmpFile);
                $embeddings[] = $result['embedding'];

                $faceModel->insert([
                    'student_id'    => $studentId,
                    'embedding'     => json_encode($result['embedding']),
                    'source'        => 'live',
                    'quality_score' => $result['quality_score'],
                ]);

                $saved++;
            } catch (\Throwable $e) {
                $errors[] = [
                    'index'  => $idx,
                    'reason' => $e->getMessage(),
                ];
            } finally {
                if (is_file($tmpFile)) {
                    @unlink($tmpFile);
                }
            }
        }

        // Optional: simpan embedding rata-rata sebagai live_avg jika ada cukup sample
        if (count($embeddings) >= 2) {
            $avg = $this->averageEmbedding($embeddings);
            $faceModel->insert([
                'student_id'    => $studentId,
                'embedding'     => json_encode($avg),
                'source'        => 'live_avg',
                'quality_score' => null,
            ]);
        }

        return $this->successResponse([
            'student_id' => $studentId,
            'saved'      => $saved,
            'errors'     => $errors,
        ], 'Enrollment live selesai');
    }

    /**
     * Hitung rata-rata beberapa embedding (elemen per elemen).
     *
     * @param array<int, array<int,float>> $vectors
     * @return float[]
     */
    protected function averageEmbedding(array $vectors): array
    {
        $count = count($vectors);
        if ($count === 0) {
            return [];
        }
        $dim = count($vectors[0]);
        $sum = array_fill(0, $dim, 0.0);
        foreach ($vectors as $vec) {
            for ($i = 0; $i < $dim; $i++) {
                $sum[$i] += (float) $vec[$i];
            }
        }
        for ($i = 0; $i < $dim; $i++) {
            $sum[$i] /= $count;
        }
        return $sum;
    }

    /**
     * Decode string base64 (data URL atau plain base64) ke binary.
     */
    protected function decodeBase64Image(string $input): ?string
    {
        $input = trim($input);
        if ($input === '') {
            return null;
        }
        if (strpos($input, 'base64,') !== false) {
            $parts = explode('base64,', $input, 2);
            $input = $parts[1];
        }
        $data = base64_decode($input, true);
        return $data === false ? null : $data;
    }
}

