<?php
defined('BASEPATH') OR exit('No direct script access allowed');

require APPPATH . 'libraries/RestController.php';
require APPPATH . 'libraries/Format.php';

use chriskacerguis\RestServer\RestController;

class Hikvision extends RestController {
    
    function __construct() {
        parent::__construct();
        $this->load->helper('session');
        $this->load->model('hikvision_model');
        $this->load->model('tags_model');
        $this->load->library('hikvision_isapi_library');
    }

    /**
     * Obtiene todos los dispositivos configurados
     */
    public function get_devices_get() {
        $devices = $this->hikvision_model->get_all_devices();
        
        if ($devices) {
            $this->response([
                'devices' => $devices,
                'error' => false
            ], RestController::HTTP_OK);
        } else {
            $this->response([
                'devices' => [],
                'message' => 'No se encontraron dispositivos configurados',
                'error' => false
            ], RestController::HTTP_OK);
        }
    }

    /**
     * Registra un nuevo dispositivo
     */
    public function register_device_post() {
        $this->_validate_device_data();
        
        $data = array(
            'nombre' => $this->post('nombre'),
            'ip_address' => $this->post('ip_address'),
            'puerto' => $this->post('puerto'),
            'usuario' => $this->post('usuario'),
            'password' => $this->post('password'),
            'ubicacion' => $this->post('ubicacion'),
            'tipo_acceso' => $this->post('tipo_acceso'),
            'status' => 1
        );

        $device_id = $this->hikvision_model->insert_device($data);
        
        if ($device_id) {
            $this->response([
                'message' => 'Dispositivo registrado correctamente',
                'device_id' => $device_id,
                'error' => false
            ], RestController::HTTP_OK);
        } else {
            $this->response([
                'message' => 'Error al registrar el dispositivo',
                'error' => true
            ], RestController::HTTP_INTERNAL_ERROR);
        }
    }

    /**
     * Actualiza un dispositivo existente
     */
    public function update_device_post() {
        $this->_validate_device_id();
        $this->_validate_device_data();
        
        $data = array(
            'nombre' => $this->post('nombre'),
            'ip_address' => $this->post('ip_address'),
            'puerto' => $this->post('puerto'),
            'usuario' => $this->post('usuario'),
            'ubicacion' => $this->post('ubicacion'),
            'tipo_acceso' => $this->post('tipo_acceso')
        );

        // Solo actualizar password si se proporciona uno nuevo
        if ($this->post('password')) {
            $data['password'] = $this->post('password');
        }

        if ($this->hikvision_model->update_device($this->get('id'), $data)) {
            $this->response([
                'message' => 'Dispositivo actualizado correctamente',
                'error' => false
            ], RestController::HTTP_OK);
        } else {
            $this->response([
                'message' => 'Error al actualizar el dispositivo',
                'error' => true
            ], RestController::HTTP_INTERNAL_ERROR);
        }
    }

    /**
     * Sincroniza con los dispositivos Hikvision
     */
    public function sincronizar_post() {
        $hours_back = $this->post('hours_back') ?: 1;
        
        $result = $this->hikvision_model->sync_all_devices_events($hours_back);
        
        if ($result['success']) {
            $this->response([
                'message' => "Sincronización completada. {$result['total_events']} eventos procesados de {$result['devices_processed']} dispositivos",
                'data' => $result,
                'error' => false
            ], RestController::HTTP_OK);
        } else {
            $this->response([
                'message' => 'Error al sincronizar con Hikvision',
                'data' => $result,
                'error' => true
            ], RestController::HTTP_INTERNAL_ERROR);
        }
    }

    /**
     * Obtiene movimientos con filtros mejorados
     */
    public function get_movements_get() {
        $filters = array(
            'fecha_inicio' => $this->get('fecha_inicio'),
            'fecha_fin' => $this->get('fecha_fin'),
            'tag_id' => $this->get('tag_id'),
            'device_id' => $this->get('device_id'),
            'processed' => $this->get('processed'),
            'tipo_movimiento' => $this->get('tipo_movimiento'),
            'access_result' => $this->get('access_result'),
            'door_id' => $this->get('door_id'),
            'numero_tag' => $this->get('numero_tag'),
            'limit' => $this->get('limit', 50),
            'offset' => $this->get('offset', 0),
            'order_by' => $this->get('order_by', 'fecha_movimiento'),
            'order_dir' => $this->get('order_dir', 'DESC')
        );

        $movements = $this->hikvision_model->get_movements_by_filters($filters);
        $total = $this->hikvision_model->count_movements($filters);

        $this->response([
            'movements' => $movements,
            'total' => $total,
            'filters_applied' => array_filter($filters, function($value) {
                return $value !== null && $value !== '';
            }),
            'error' => false
        ], RestController::HTTP_OK);
    }

    /**
     * Registra un nuevo movimiento
     */
    public function register_movement_post() {
        $this->_validate_movement_data();
        
        // Verificar que el TAG existe
        $tag = $this->tags_model->get_tag_by_id($this->post('tag_id'));
        if (!$tag) {
            $this->response([
                'message' => 'TAG no encontrado',
                'error' => true
            ], RestController::HTTP_NOT_FOUND);
            return;
        }

        $data = array(
            'tag_id' => $this->post('tag_id'),
            'device_id' => $this->post('device_id'),
            'fecha_movimiento' => date('Y-m-d H:i:s'),
            'tipo_movimiento' => $this->post('tipo_movimiento'),
            'processed' => 0
        );

        $movement_id = $this->hikvision_model->register_movement($data);
        
        if ($movement_id) {
            $this->response([
                'message' => 'Movimiento registrado correctamente',
                'movement_id' => $movement_id,
                'error' => false
            ], RestController::HTTP_OK);
        } else {
            $this->response([
                'message' => 'Error al registrar el movimiento',
                'error' => true
            ], RestController::HTTP_INTERNAL_ERROR);
        }
    }

    // ================== NUEVOS ENDPOINTS PARA CONTROL DE ACCESO ISAPI ==================

    /**
     * Prueba la conexión con un dispositivo específico
     */
    public function test_device_connection_get() {
        $this->_validate_device_id();
        
        $device_id = $this->get('id');
        $result = $this->hikvision_model->connect_device_isapi($device_id);
        
        if ($result['success']) {
            $this->response([
                'message' => $result['message'],
                'device_info' => $result['device_info'] ?? null,
                'error' => false
            ], RestController::HTTP_OK);
        } else {
            $this->response([
                'message' => $result['message'],
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
        }
    }

    /**
     * Obtiene eventos de acceso de un dispositivo específico
     */
    public function get_device_events_get() {
        $this->_validate_device_id();
        
        $device_id = $this->get('id');
        $start_time = $this->get('start_time');
        $end_time = $this->get('end_time');
        
        // Si no se especifican fechas, usar la última hora
        if (!$start_time) {
            $start_time = date('Y-m-d\TH:i:s\Z', strtotime('-1 hour'));
        }
        if (!$end_time) {
            $end_time = date('Y-m-d\TH:i:s\Z');
        }
        
        $result = $this->hikvision_model->get_device_access_events($device_id, $start_time, $end_time);
        
        if ($result['success']) {
            $this->response([
                'events' => $result['events'],
                'total' => $result['total'],
                'raw_events' => $result['raw_events'] ?? [],
                'error' => false
            ], RestController::HTTP_OK);
        } else {
            $this->response([
                'message' => $result['message'],
                'events' => [],
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
        }
    }

    /**
     * Abre una puerta específica del dispositivo (Control de barrera)
     */
    public function open_door_post() {
        $this->_validate_device_id();
        $this->load->library('form_validation');
        
        $this->form_validation->set_rules('door_id', 'Door ID', 'integer');
        $this->form_validation->set_rules('reason', 'Razón', 'max_length[255]');
        
        if (!$this->form_validation->run()) {
            $this->response([
                'message' => validation_errors(),
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
            return;
        }
        
        $device_id = $this->get('id');
        $door_id = $this->post('door_id') ?: 2; // Por defecto puerta 2 (barrera)
        $reason = $this->post('reason') ?: 'Control manual desde sistema';
        
        $result = $this->hikvision_model->open_device_door($device_id, $door_id, $reason);
        
        if ($result['success']) {
            $this->response([
                'message' => $result['message'],
                'timestamp' => $result['timestamp'],
                'error' => false
            ], RestController::HTTP_OK);
        } else {
            $this->response([
                'message' => $result['message'],
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
        }
    }

    /**
     * Obtiene el estado actual de las puertas del dispositivo
     */
    public function get_door_status_get() {
        $this->_validate_device_id();
        
        $device_id = $this->get('id');
        $result = $this->hikvision_model->get_device_door_status($device_id);
        
        if ($result['success']) {
            $this->response([
                'doors' => $result['doors'],
                'error' => false
            ], RestController::HTTP_OK);
        } else {
            $this->response([
                'message' => $result['message'],
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
        }
    }

    /**
     * Configura el modo de trabajo de una puerta
     */
    public function set_door_mode_post() {
        $this->_validate_device_id();
        $this->load->library('form_validation');
        
        $this->form_validation->set_rules('mode', 'Modo', 'required|in_list[normal,free,forbidden]');
        $this->form_validation->set_rules('door_id', 'Door ID', 'integer');
        
        if (!$this->form_validation->run()) {
            $this->response([
                'message' => validation_errors(),
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
            return;
        }
        
        $device_id = $this->get('id');
        $mode = $this->post('mode');
        $door_id = $this->post('door_id') ?: 1; // Por defecto puerta 1 (lectura)
        
        $result = $this->hikvision_model->set_device_door_mode($device_id, $mode, $door_id);
        
        if ($result['success']) {
            $this->response([
                'message' => $result['message'],
                'error' => false
            ], RestController::HTTP_OK);
        } else {
            $this->response([
                'message' => $result['message'],
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
        }
    }

    /**
     * Valida un TAG específico para acceso
     */
    public function validate_tag_post() {
        $this->load->library('form_validation');
        
        $this->form_validation->set_rules('card_no', 'Número de Tarjeta', 'required|max_length[50]');
        
        if (!$this->form_validation->run()) {
            $this->response([
                'message' => validation_errors(),
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
            return;
        }
        
        $card_no = $this->post('card_no');
        $result = $this->hikvision_model->validate_tag_access($card_no);
        
        $this->response([
            'valid' => $result['valid'],
            'access_granted' => $result['access_granted'],
            'tag_data' => $result['tag_data'],
            'saldo_suficiente' => $result['saldo_suficiente'],
            'error' => false
        ], RestController::HTTP_OK);
    }

    /**
     * Procesa un evento de acceso manualmente
     */
    public function process_access_event_post() {
        $this->_validate_device_id();
        $this->load->library('form_validation');
        
        $this->form_validation->set_rules('card_no', 'Número de Tarjeta', 'required|max_length[50]');
        $this->form_validation->set_rules('door_id', 'Door ID', 'required|integer');
        $this->form_validation->set_rules('event_time', 'Tiempo del Evento', 'required');
        
        if (!$this->form_validation->run()) {
            $this->response([
                'message' => validation_errors(),
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
            return;
        }
        
        $device_id = $this->get('id');
        $event_data = [
            'card_no' => $this->post('card_no'),
            'door_id' => $this->post('door_id'),
            'event_time' => $this->post('event_time'),
            'event_id' => $this->post('event_id') ?: uniqid('manual_'),
            'event_type' => $this->post('event_type') ?: 'card_access'
        ];
        
        $result = $this->hikvision_model->process_access_event($device_id, $event_data);
        
        if ($result['success']) {
            $this->response([
                'message' => $result['message'],
                'action' => $result['action'],
                'tag_data' => $result['tag_data'] ?? null,
                'movement_id' => $result['movement_id'] ?? null,
                'error' => false
            ], RestController::HTTP_OK);
        } else {
            $this->response([
                'message' => $result['message'],
                'action' => $result['action'],
                'error' => false // No es error, solo acceso denegado
            ], RestController::HTTP_OK);
        }
    }

    /**
     * Endpoint para recibir webhooks/eventos de Hikvision (si se configura)
     */
    public function webhook_event_post() {
        $raw_input = file_get_contents('php://input');
        log_message('info', 'Webhook recibido de Hikvision: ' . $raw_input);
        
        try {
            // Intentar parsear como JSON
            $event_data = json_decode($raw_input, true);
            
            if ($event_data && isset($event_data['eventType'])) {
                // Procesar evento según el tipo
                $this->_process_webhook_event($event_data);
                
                $this->response([
                    'message' => 'Evento procesado correctamente',
                    'error' => false
                ], RestController::HTTP_OK);
            } else {
                $this->response([
                    'message' => 'Formato de evento no válido',
                    'error' => true
                ], RestController::HTTP_BAD_REQUEST);
            }
        } catch (Exception $e) {
            log_message('error', 'Error procesando webhook: ' . $e->getMessage());
            $this->response([
                'message' => 'Error interno procesando evento',
                'error' => true
            ], RestController::HTTP_INTERNAL_ERROR);
        }
    }

    /**
     * Obtiene estadísticas del sistema de control de acceso
     */
    public function get_access_stats_get() {
        $fecha_inicio = $this->get('fecha_inicio') ?: date('Y-m-d');
        $fecha_fin = $this->get('fecha_fin') ?: date('Y-m-d');
        
        // Estadísticas básicas
        $stats = [
            'total_movimientos' => $this->hikvision_model->count_movements([
                'fecha_inicio' => $fecha_inicio,
                'fecha_fin' => $fecha_fin
            ]),
            'movimientos_entrada' => $this->hikvision_model->count_movements([
                'fecha_inicio' => $fecha_inicio,
                'fecha_fin' => $fecha_fin,
                'tipo_movimiento' => 'ENTRADA'
            ]),
            'movimientos_salida' => $this->hikvision_model->count_movements([
                'fecha_inicio' => $fecha_inicio,
                'fecha_fin' => $fecha_fin,
                'tipo_movimiento' => 'SALIDA'
            ]),
            'dispositivos_activos' => count($this->hikvision_model->get_all_devices()),
            'fecha_consulta' => date('Y-m-d H:i:s')
        ];
        
        $this->response([
            'stats' => $stats,
            'error' => false
        ], RestController::HTTP_OK);
    }

    /**
     * Exportar movimientos a Excel
     */
    public function export_movements_excel_get() {
        $filters = array(
            'fecha_inicio' => $this->get('fecha_inicio'),
            'fecha_fin' => $this->get('fecha_fin'),
            'tag_id' => $this->get('tag_id'),
            'device_id' => $this->get('device_id'),
            'processed' => $this->get('processed'),
            'tipo_movimiento' => $this->get('tipo_movimiento')
        );

        $movements = $this->hikvision_model->get_movements_by_filters($filters);

        if (empty($movements)) {
            $this->response([
                'message' => 'No hay datos para exportar',
                'error' => true
            ], RestController::HTTP_OK);
            return;
        }

        try {
            require_once APPPATH . '../vendor/autoload.php';
            
            $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
            $sheet = $spreadsheet->getActiveSheet();
            
            // Encabezados
            $sheet->setCellValue('A1', 'TAG');
            $sheet->setCellValue('B1', 'Número Económico');
            $sheet->setCellValue('C1', 'Modalidad');
            $sheet->setCellValue('D1', 'Dispositivo');
            $sheet->setCellValue('E1', 'Ubicación');
            $sheet->setCellValue('F1', 'Tipo Movimiento');
            $sheet->setCellValue('G1', 'Fecha y Hora');
            $sheet->setCellValue('H1', 'Procesado');
            
            // Estilo para encabezados
            $styleHeader = [
                'font' => [
                    'bold' => true,
                    'color' => ['rgb' => 'FFFFFF'],
                ],
                'fill' => [
                    'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                    'color' => ['rgb' => '4F81BD'],
                ],
                'alignment' => [
                    'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
                ],
            ];
            $sheet->getStyle('A1:H1')->applyFromArray($styleHeader);
            
            // Datos
            $row = 2;
            foreach ($movements as $mov) {
                $sheet->setCellValue('A' . $row, $mov['numero_tag']);
                $sheet->setCellValue('B' . $row, $mov['numero_economico'] ?? 'N/A');
                $sheet->setCellValue('C' . $row, $mov['modalidad_nombre'] ?? 'N/A');
                $sheet->setCellValue('D' . $row, $mov['dispositivo']);
                $sheet->setCellValue('E' . $row, $mov['ubicacion']);
                $sheet->setCellValue('F' . $row, $mov['tipo_movimiento']);
                $sheet->setCellValue('G' . $row, date('d/m/Y H:i:s', strtotime($mov['fecha_movimiento'])));
                $sheet->setCellValue('H' . $row, $mov['processed'] ? 'Sí' : 'No');
                $row++;
            }
            
            // Autoajustar columnas
            foreach(range('A', 'H') as $col) {
                $sheet->getColumnDimension($col)->setAutoSize(true);
            }
            
            // Guardar archivo
            $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
            $filename = 'movimientos_tags_' . date('YmdHis') . '.xlsx';
            $filepath = FCPATH . 'uploads/' . $filename;
            
            if (!is_dir(FCPATH . 'uploads')) {
                mkdir(FCPATH . 'uploads', 0777, true);
            }
            
            $writer->save($filepath);
            
            $this->response([
                'url' => base_url('uploads/' . $filename),
                'error' => false
            ], RestController::HTTP_OK);
            
        } catch (\Exception $e) {
            log_message('error', 'Error al generar Excel: ' . $e->getMessage());
            $this->response([
                'message' => 'Error al generar el Excel: ' . $e->getMessage(),
                'error' => true
            ], RestController::HTTP_INTERNAL_ERROR);
        }
    }

    /**
     * Exportar movimientos a PDF
     */
    public function export_movements_pdf_get() {
        $filters = array(
            'fecha_inicio' => $this->get('fecha_inicio'),
            'fecha_fin' => $this->get('fecha_fin'),
            'tag_id' => $this->get('tag_id'),
            'device_id' => $this->get('device_id'),
            'processed' => $this->get('processed'),
            'tipo_movimiento' => $this->get('tipo_movimiento')
        );

        $movements = $this->hikvision_model->get_movements_by_filters($filters);

        if (empty($movements)) {
            $this->response([
                'message' => 'No hay datos para exportar',
                'error' => true
            ], RestController::HTTP_OK);
            return;
        }

        try {
            require_once APPPATH . '../vendor/autoload.php';
            
            $mpdf = new \Mpdf\Mpdf([
                'format' => 'A4-L',
                'margin_left' => 10,
                'margin_right' => 10,
                'margin_top' => 15,
                'margin_bottom' => 15
            ]);
            
            $mpdf->SetTitle('Reporte de Movimientos TAGs');
            
            // Preparar datos para la vista
            $data = [
                'movements' => $movements,
                'filters' => $filters,
                'fecha_generacion' => date('Y-m-d H:i:s'),
                'base_url' => base_url()
            ];
            
            // Cargar vista
            $html = $this->load->view('hikvision/movimientos_pdf', $data, TRUE);
            
            $mpdf->WriteHTML($html);
            
            // Generar archivo
            $filename = 'movimientos_tags_' . date('YmdHis') . '.pdf';
            $mpdf->Output($filename, \Mpdf\Output\Destination::INLINE);
            
        } catch (\Exception $e) {
            log_message('error', 'Error al generar PDF: ' . $e->getMessage());
            $this->response([
                'message' => 'Error al generar el PDF: ' . $e->getMessage(),
                'error' => true
            ], RestController::HTTP_INTERNAL_ERROR);
        }
    }

    // ================== MÉTODOS PRIVADOS ==================

    /**
     * Procesa eventos recibidos por webhook
     */
    private function _process_webhook_event($event_data) {
        // Lógica para procesar eventos de webhook
        // Esto se puede implementar según las necesidades específicas
        log_message('info', 'Procesando evento webhook: ' . json_encode($event_data));
    }

    /**
     * Validaciones existentes
     */
    private function _validate_device_data() {
        $this->load->library('form_validation');
        
        $this->form_validation->set_rules('nombre', 'Nombre', 'required|max_length[100]');
        $this->form_validation->set_rules('ip_address', 'Dirección IP', 'required|valid_ip|max_length[45]');
        $this->form_validation->set_rules('puerto', 'Puerto', 'required|integer');
        $this->form_validation->set_rules('usuario', 'Usuario', 'required|max_length[50]');
        $this->form_validation->set_rules('ubicacion', 'Ubicación', 'max_length[100]');
        $this->form_validation->set_rules('tipo_acceso', 'Tipo de Acceso', 'required|in_list[ENTRADA,SALIDA]');
        
        if (!$this->form_validation->run()) {
            $this->response([
                'message' => validation_errors(),
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
        }
    }
    
    private function _validate_device_id() {
        $this->load->library('form_validation');
        
        $this->form_validation->set_rules('id', 'ID', 'required|integer');
        
        if (!$this->form_validation->run()) {
            $this->response([
                'message' => validation_errors(),
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
        }
    }

    private function _validate_movement_data() {
        $this->load->library('form_validation');
        
        $this->form_validation->set_rules('tag_id', 'TAG ID', 'required|integer');
        $this->form_validation->set_rules('device_id', 'Device ID', 'required|integer');
        $this->form_validation->set_rules('tipo_movimiento', 'Tipo de Movimiento', 'required|in_list[ENTRADA,SALIDA]');
        
        if (!$this->form_validation->run()) {
            $this->response([
                'message' => validation_errors(),
                'error' => true
            ], RestController::HTTP_BAD_REQUEST);
        }
    }
}