<?php
declare(strict_types=1);

namespace App\Modules\HR\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Modules\HR\Services\BiometricService;

class BiometricController extends Controller
{
    /**
     * List all biometric devices with last_sync_at.
     */
    public function devices(Request $request): Response
    {
        $this->authorize('hr.biometric.view');

        $db = App::getInstance()->db();

        $devices = $db->select(
            "SELECT d.*, b.name_ar as branch_name
             FROM hr_biometric_devices d
             LEFT JOIN branches b ON b.id = d.branch_id
             ORDER BY d.is_active DESC, d.device_name ASC"
        );

        return $this->view('HR.Views.biometric.devices', [
            'devices' => $devices,
        ]);
    }

    /**
     * Show form to add a new device.
     */
    public function createDevice(Request $request): Response
    {
        $this->authorize('hr.biometric.manage');

        $db = App::getInstance()->db();
        $branches = $db->select("SELECT id, name_ar FROM branches WHERE is_archived = 0 ORDER BY name_ar");

        return $this->view('HR.Views.biometric.device_form', [
            'device'   => null,
            'branches' => $branches,
        ]);
    }

    /**
     * Validate and insert a new biometric device.
     */
    public function storeDevice(Request $request): Response
    {
        $this->authorize('hr.biometric.manage');

        $data = $this->extractDeviceData($request);
        $errors = $this->validateDeviceData($data);

        if (!empty($errors)) {
            return $this->flashErrorsAndRedirect($errors, $request, '/hr/biometric/devices/create');
        }

        $db = App::getInstance()->db();
        $db->insert('hr_biometric_devices', [
            'device_name'          => $data['device_name'],
            'device_type'          => $data['device_type'],
            'ip_address'           => $data['ip_address'] ?: null,
            'port'                 => $data['port'] > 0 ? $data['port'] : null,
            'serial_number'        => $data['serial_number'] ?: null,
            'location_description' => $data['location_description'] ?: null,
            'branch_id'            => $data['branch_id'] > 0 ? $data['branch_id'] : null,
            'is_active'            => $data['is_active'],
            'created_at'           => date('Y-m-d H:i:s'),
            'updated_at'           => date('Y-m-d H:i:s'),
        ]);

        return $this->redirect('/hr/biometric/devices')->withSuccess('تم إضافة الجهاز بنجاح');
    }

    /**
     * Show edit form for a device.
     */
    public function editDevice(Request $request, int $id): Response
    {
        $this->authorize('hr.biometric.manage');

        $db = App::getInstance()->db();
        $device = $db->selectOne("SELECT * FROM hr_biometric_devices WHERE id = ?", [$id]);

        if (!$device) {
            return $this->redirect('/hr/biometric/devices')->withError('الجهاز غير موجود');
        }

        $branches = $db->select("SELECT id, name_ar FROM branches WHERE is_archived = 0 ORDER BY name_ar");

        return $this->view('HR.Views.biometric.device_form', [
            'device'   => $device,
            'branches' => $branches,
        ]);
    }

    /**
     * Update a biometric device.
     */
    public function updateDevice(Request $request, int $id): Response
    {
        $this->authorize('hr.biometric.manage');

        $db = App::getInstance()->db();
        $device = $db->selectOne("SELECT * FROM hr_biometric_devices WHERE id = ?", [$id]);

        if (!$device) {
            return $this->redirect('/hr/biometric/devices')->withError('الجهاز غير موجود');
        }

        $data = $this->extractDeviceData($request);
        $errors = $this->validateDeviceData($data, $id);

        if (!empty($errors)) {
            return $this->flashErrorsAndRedirect($errors, $request, '/hr/biometric/devices/' . $id . '/edit');
        }

        $db->update('hr_biometric_devices', [
            'device_name'          => $data['device_name'],
            'device_type'          => $data['device_type'],
            'ip_address'           => $data['ip_address'] ?: null,
            'port'                 => $data['port'] > 0 ? $data['port'] : null,
            'serial_number'        => $data['serial_number'] ?: null,
            'location_description' => $data['location_description'] ?: null,
            'branch_id'            => $data['branch_id'] > 0 ? $data['branch_id'] : null,
            'is_active'            => $data['is_active'],
            'updated_at'           => date('Y-m-d H:i:s'),
        ], '`id` = ?', [$id]);

        return $this->redirect('/hr/biometric/devices')->withSuccess('تم تحديث بيانات الجهاز بنجاح');
    }

    /**
     * Soft delete a device (set is_active = 0).
     */
    public function deleteDevice(Request $request, int $id): Response
    {
        $this->authorize('hr.biometric.manage');

        $db = App::getInstance()->db();
        $device = $db->selectOne("SELECT * FROM hr_biometric_devices WHERE id = ?", [$id]);

        if (!$device) {
            return $this->redirect('/hr/biometric/devices')->withError('الجهاز غير موجود');
        }

        $db->update('hr_biometric_devices', [
            'is_active'  => 0,
            'updated_at' => date('Y-m-d H:i:s'),
        ], '`id` = ?', [$id]);

        return $this->redirect('/hr/biometric/devices')->withSuccess('تم تعطيل الجهاز بنجاح');
    }

    /**
     * List recent biometric punches with filters.
     */
    public function punches(Request $request): Response
    {
        $this->authorize('hr.biometric.view');

        $db = App::getInstance()->db();

        $filters = [
            'date_from'  => trim((string) $request->get('date_from', date('Y-m-d', strtotime('-7 days')))),
            'date_to'    => trim((string) $request->get('date_to', date('Y-m-d'))),
            'device_id'  => (int) $request->get('device_id', 0),
            'processed'  => trim((string) $request->get('processed', '')),
        ];

        $page = max(1, (int) $request->get('page', 1));
        $perPage = 50;
        $offset = ($page - 1) * $perPage;

        $where = "WHERE p.punch_time >= ? AND p.punch_time < DATE_ADD(?, INTERVAL 1 DAY)";
        $params = [$filters['date_from'], $filters['date_to']];

        if ($filters['device_id'] > 0) {
            $where .= " AND p.device_id = ?";
            $params[] = $filters['device_id'];
        }

        if ($filters['processed'] !== '') {
            $where .= " AND p.processed = ?";
            $params[] = (int) $filters['processed'];
        }

        // Count total
        $countRow = $db->selectOne(
            "SELECT COUNT(*) as total FROM hr_biometric_punches p $where",
            $params
        );
        $total = (int) ($countRow['total'] ?? 0);

        // Fetch page
        $punches = $db->select(
            "SELECT p.*, d.device_name,
                    hp.first_name_ar, hp.last_name_ar, hp.employee_number
             FROM hr_biometric_punches p
             JOIN hr_biometric_devices d ON d.id = p.device_id
             LEFT JOIN hr_employee_profiles hp ON hp.fingerprint_code = p.fingerprint_code AND hp.is_archived = 0
             $where
             ORDER BY p.punch_time DESC
             LIMIT $perPage OFFSET $offset",
            $params
        );

        // Devices for filter dropdown
        $devices = $db->select("SELECT id, device_name FROM hr_biometric_devices ORDER BY device_name");

        $pagination = [
            'current_page' => $page,
            'per_page'     => $perPage,
            'total'        => $total,
            'last_page'    => (int) ceil($total / $perPage),
        ];

        return $this->view('HR.Views.biometric.punches', [
            'punches'    => $punches,
            'pagination' => $pagination,
            'filters'    => $filters,
            'devices'    => $devices,
        ]);
    }

    /**
     * API endpoint to receive a punch from a biometric device.
     * No auth middleware — device authentication via serial_number.
     * Accepts JSON body: {device_serial, fingerprint_code, punch_time, punch_type}
     */
    public function receivePunch(Request $request): Response
    {
        $body = json_decode(file_get_contents('php://input'), true);

        if (!is_array($body)) {
            return $this->json(['success' => false, 'error' => 'Invalid JSON body']);
        }

        $result = BiometricService::processPunch($body);

        return $this->json($result);
    }

    /**
     * Manually trigger processing of all unprocessed punches.
     */
    public function processAll(Request $request): Response
    {
        $this->authorize('hr.biometric.manage');

        $result = BiometricService::processAllPending();

        return $this->redirect('/hr/biometric/punches?processed=0')
            ->withSuccess("تمت معالجة البصمات: {$result['processed']} ناجح، {$result['failed']} فاشل");
    }

    // ─── Private helpers ─────────────────────────────────────────

    private function extractDeviceData(Request $request): array
    {
        return [
            'device_name'          => trim((string) $request->post('device_name', '')),
            'device_type'          => trim((string) $request->post('device_type', 'fingerprint')),
            'ip_address'           => trim((string) $request->post('ip_address', '')),
            'port'                 => (int) $request->post('port', 0),
            'serial_number'        => trim((string) $request->post('serial_number', '')),
            'location_description' => trim((string) $request->post('location_description', '')),
            'branch_id'            => (int) $request->post('branch_id', 0),
            'is_active'            => (int) ($request->post('is_active', 1)),
        ];
    }

    private function validateDeviceData(array $data, ?int $excludeId = null): array
    {
        $errors = [];

        if ($data['device_name'] === '' || mb_strlen($data['device_name']) < 2) {
            $errors[] = 'اسم الجهاز مطلوب';
        }

        if (!in_array($data['device_type'], ['fingerprint', 'face', 'card'], true)) {
            $errors[] = 'نوع الجهاز غير صالح';
        }

        // Check serial_number uniqueness if provided
        if ($data['serial_number'] !== '') {
            $db = App::getInstance()->db();
            $query = "SELECT id FROM hr_biometric_devices WHERE serial_number = ?";
            $params = [$data['serial_number']];

            if ($excludeId !== null) {
                $query .= " AND id != ?";
                $params[] = $excludeId;
            }

            $existing = $db->selectOne($query, $params);
            if ($existing) {
                $errors[] = 'الرقم التسلسلي مستخدم بالفعل في جهاز آخر';
            }
        }

        return $errors;
    }

    private function flashErrorsAndRedirect(array $errors, Request $request, string $url): Response
    {
        $session = App::getInstance()->session();
        $session->flash('_alerts', array_map(fn($e) => ['type' => 'error', 'message' => $e], $errors));
        $session->flash('_old_input', $request->all());
        return $this->redirect($url);
    }
}
