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

class Hikvision_model extends CI_Model {
    
    public function __construct() {
        parent::__construct();
        $this->load->database();
        $this->load->library('hikvision_isapi_library');
        $this->devices_table = 'hikvision_devices';
        $this->movements_table = 'tags_movimientos_hikvision';
        $this->access_logs_table = 'hikvision_access_logs';
    }

    /**
     * Obtiene todos los dispositivos configurados
     */
    public function get_all_devices() {
        $this->db->select('*');
        $this->db->from($this->devices_table);
        $this->db->where('status', 1);
        $this->db->order_by('nombre', 'ASC');
        
        $query = $this->db->get();
        return $query->result_array();
    }

    /**
     * Obtiene un dispositivo por ID
     */
    public function get_device_by_id($id) {
        $this->db->where('id', $id);
        $query = $this->db->get($this->devices_table);
        return $query->row_array();
    }

    /**
     * Inserta un nuevo dispositivo
     */
    public function insert_device($data) {
        $data['created_at'] = date('Y-m-d H:i:s');
        
        if ($this->db->insert($this->devices_table, $data)) {
            $id = $this->db->insert_id();
            if (create_log($this->devices_table, $id, $data)) {
                return $id;
            }
        }
        return FALSE;
    }

    /**
     * Actualiza un dispositivo existente
     */
    public function update_device($id, $data) {
        $data['updated_at'] = date('Y-m-d H:i:s');
        
        $this->db->where('id', $id);
        if ($this->db->update($this->devices_table, $data)) {
            if (create_log($this->devices_table, $id, $data)) {
                return TRUE;
            }
        }
        return FALSE;
    }

    /**
     * Registra un nuevo movimiento detectado por Hikvision
     */
    public function register_movement($data) {
        $data['created_at'] = date('Y-m-d H:i:s');
        
        if ($this->db->insert($this->movements_table, $data)) {
            $id = $this->db->insert_id();
            if (create_log($this->movements_table, $id, $data)) {
                return $id;
            }
        }
        return FALSE;
    }

    /**
     * Obtiene movimientos con filtros mejorados
     */
    public function get_movements_by_filters($filters = array()) {
        $this->db->select('tmh.*, t.numero_tag, hd.nombre as dispositivo, hd.ubicacion, 
                          ne.numero_economico, ne.modalidad_nombre');
        $this->db->from($this->movements_table . ' tmh');
        $this->db->join('tags t', 't.id = tmh.tag_id');
        $this->db->join('hikvision_devices hd', 'hd.id = tmh.device_id');
        $this->db->join('tags_numeros_economicos tne', 'tne.tag_id = t.id AND tne.status = 1', 'left');
        $this->db->join('numeros_economicos ne', 'ne.id = tne.numero_economico_id', 'left');

        // Aplicar filtros existentes
        if (!empty($filters['fecha_inicio'])) {
            $this->db->where('DATE(tmh.fecha_movimiento) >=', $filters['fecha_inicio']);
        }
        if (!empty($filters['fecha_fin'])) {
            $this->db->where('DATE(tmh.fecha_movimiento) <=', $filters['fecha_fin']);
        }
        if (!empty($filters['tag_id'])) {
            $this->db->where('tmh.tag_id', $filters['tag_id']);
        }
        if (!empty($filters['device_id'])) {
            $this->db->where('tmh.device_id', $filters['device_id']);
        }
        if (isset($filters['processed']) && $filters['processed'] !== '') {
            $this->db->where('tmh.processed', $filters['processed']);
        }
        if (!empty($filters['tipo_movimiento'])) {
            $this->db->where('tmh.tipo_movimiento', $filters['tipo_movimiento']);
        }

        // Nuevos filtros para ISAPI
        if (!empty($filters['access_result'])) {
            $this->db->where('tmh.access_result', $filters['access_result']);
        }
        if (!empty($filters['door_id'])) {
            $this->db->where('tmh.door_id', $filters['door_id']);
        }
        if (!empty($filters['numero_tag'])) {
            $this->db->like('t.numero_tag', $filters['numero_tag']);
        }

        // Ordenamiento y límites
        if (!empty($filters['order_by'])) {
            $this->db->order_by($filters['order_by'], $filters['order_dir'] ?? 'DESC');
        } else {
            $this->db->order_by('tmh.fecha_movimiento', 'DESC');
        }

        if (!empty($filters['limit'])) {
            $this->db->limit($filters['limit'], $filters['offset'] ?? 0);
        }

        $query = $this->db->get();
        return $query->result_array();
    }

    /**
     * Cuenta total de movimientos para paginación (mejorado)
     */
    public function count_movements($filters = array()) {
        $this->db->select('COUNT(*) as total');
        $this->db->from($this->movements_table . ' tmh');
        $this->db->join('tags t', 't.id = tmh.tag_id');
        
        // Aplicar los mismos filtros que en get_movements_by_filters
        if (!empty($filters['fecha_inicio'])) {
            $this->db->where('DATE(tmh.fecha_movimiento) >=', $filters['fecha_inicio']);
        }
        if (!empty($filters['fecha_fin'])) {
            $this->db->where('DATE(tmh.fecha_movimiento) <=', $filters['fecha_fin']);
        }
        if (!empty($filters['tag_id'])) {
            $this->db->where('tmh.tag_id', $filters['tag_id']);
        }
        if (!empty($filters['device_id'])) {
            $this->db->where('tmh.device_id', $filters['device_id']);
        }
        if (isset($filters['processed']) && $filters['processed'] !== '') {
            $this->db->where('tmh.processed', $filters['processed']);
        }
        if (!empty($filters['tipo_movimiento'])) {
            $this->db->where('tmh.tipo_movimiento', $filters['tipo_movimiento']);
        }
        if (!empty($filters['access_result'])) {
            $this->db->where('tmh.access_result', $filters['access_result']);
        }
        if (!empty($filters['door_id'])) {
            $this->db->where('tmh.door_id', $filters['door_id']);
        }
        if (!empty($filters['numero_tag'])) {
            $this->db->like('t.numero_tag', $filters['numero_tag']);
        }

        $query = $this->db->get();
        $result = $query->row_array();
        return $result['total'];
    }

    /**
     * Marca un movimiento como procesado
     */
    public function mark_as_processed($movement_id) {
        $data = array(
            'processed' => 1,
            'processed_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s')
        );

        $this->db->where('id', $movement_id);
        return $this->db->update($this->movements_table, $data);
    }

    // ================== NUEVOS MÉTODOS PARA CONTROL DE ACCESO ISAPI ==================

    /**
     * Conecta y configura un dispositivo para comunicación ISAPI
     * @param int $device_id
     * @return array
     */
    public function connect_device_isapi($device_id) {
        $device = $this->get_device_by_id($device_id);
        
        if (!$device) {
            return [
                'success' => false,
                'message' => 'Dispositivo no encontrado'
            ];
        }

        $config = [
            'ip_address' => $device['ip_address'],
            'puerto' => $device['puerto'],
            'usuario' => $device['usuario'],
            'password' => $device['password']
        ];

        if ($this->hikvision_isapi_library->set_device_config($config)) {
            $connection_test = $this->hikvision_isapi_library->test_connection();
            
            if ($connection_test['success']) {
                // Actualizar último estado de conexión
                $this->update_device_connection_status($device_id, 1);
                
                return [
                    'success' => true,
                    'message' => 'Dispositivo conectado correctamente',
                    'device_info' => $connection_test['device_info']
                ];
            } else {
                $this->update_device_connection_status($device_id, 0);
                return $connection_test;
            }
        } else {
            return [
                'success' => false,
                'message' => 'Error en configuración del dispositivo'
            ];
        }
    }

    /**
     * Obtiene eventos de acceso desde el dispositivo (Puerta 1 - Lectura TAG)
     * @param int $device_id
     * @param string $start_time
     * @param string $end_time
     * @return array
     */
    public function get_device_access_events($device_id, $start_time = null, $end_time = null) {
        $connect_result = $this->connect_device_isapi($device_id);
        
        if (!$connect_result['success']) {
            return $connect_result;
        }

        $events_result = $this->hikvision_isapi_library->get_access_events($start_time, $end_time);
        
        if ($events_result['success']) {
            // Procesar y registrar eventos en la base de datos
            $processed_events = $this->_process_and_store_events($device_id, $events_result['events']);
            
            return [
                'success' => true,
                'events' => $processed_events,
                'total' => count($processed_events),
                'raw_events' => $events_result['events']
            ];
        }

        return $events_result;
    }

    /**
     * Abre la puerta del dispositivo (Puerta 2 - Control Barrera)
     * @param int $device_id
     * @param int $door_id
     * @param string $reason
     * @return array
     */
    public function open_device_door($device_id, $door_id = 2, $reason = 'Control manual') {
        $connect_result = $this->connect_device_isapi($device_id);
        
        if (!$connect_result['success']) {
            return $connect_result;
        }

        $open_result = $this->hikvision_isapi_library->open_door($door_id);
        
        if ($open_result['success']) {
            // Registrar la acción en logs
            $this->log_door_action($device_id, $door_id, 'OPEN', $reason);
        }

        return $open_result;
    }

    /**
     * Obtiene el estado actual de las puertas del dispositivo
     * @param int $device_id
     * @return array
     */
    public function get_device_door_status($device_id) {
        $connect_result = $this->connect_device_isapi($device_id);
        
        if (!$connect_result['success']) {
            return $connect_result;
        }

        return $this->hikvision_isapi_library->get_door_status();
    }

    /**
     * Configura el modo de trabajo de una puerta
     * @param int $device_id
     * @param string $mode
     * @param int $door_id
     * @return array
     */
    public function set_device_door_mode($device_id, $mode = 'normal', $door_id = 1) {
        $connect_result = $this->connect_device_isapi($device_id);
        
        if (!$connect_result['success']) {
            return $connect_result;
        }

        $mode_result = $this->hikvision_isapi_library->set_door_mode($mode, $door_id);
        
        if ($mode_result['success']) {
            $this->log_door_action($device_id, $door_id, 'MODE_CHANGE', "Modo cambiado a: {$mode}");
        }

        return $mode_result;
    }

    /**
     * Sincroniza eventos desde todos los dispositivos activos
     * @param int $hours_back - Horas hacia atrás para sincronizar
     * @return array
     */
    public function sync_all_devices_events($hours_back = 1) {
        $devices = $this->get_all_devices();
        $results = [];
        $total_events = 0;

        $start_time = date('Y-m-d\TH:i:s\Z', strtotime("-{$hours_back} hours"));
        $end_time = date('Y-m-d\TH:i:s\Z');

        foreach ($devices as $device) {
            $device_result = $this->get_device_access_events($device['id'], $start_time, $end_time);
            
            $results[] = [
                'device_id' => $device['id'],
                'device_name' => $device['nombre'],
                'success' => $device_result['success'],
                'events_count' => $device_result['success'] ? $device_result['total'] : 0,
                'message' => $device_result['message'] ?? 'OK'
            ];

            if ($device_result['success']) {
                $total_events += $device_result['total'];
            }
        }

        return [
            'success' => true,
            'total_events' => $total_events,
            'devices_processed' => count($devices),
            'results' => $results
        ];
    }

    /**
     * Busca un TAG en la base de datos y valida acceso
     * @param string $card_no - Número de tarjeta/TAG
     * @return array
     */
    public function validate_tag_access($card_no) {
        $this->db->select('t.*, ne.numero_economico, ne.modalidad_nombre, ne.status as ne_status');
        $this->db->from('tags t');
        $this->db->join('tags_numeros_economicos tne', 'tne.tag_id = t.id AND tne.status = 1', 'left');
        $this->db->join('numeros_economicos ne', 'ne.id = tne.numero_economico_id', 'left');
        $this->db->where('t.numero_tag', $card_no);
        $this->db->where('t.status', 1);
        
        $query = $this->db->get();
        $tag_data = $query->row_array();

        if ($tag_data) {
            // Verificar saldo si es necesario
            $saldo_suficiente = $this->_check_tag_balance($tag_data['id']);
            
            return [
                'valid' => true,
                'tag_data' => $tag_data,
                'saldo_suficiente' => $saldo_suficiente,
                'access_granted' => $saldo_suficiente && $tag_data['ne_status'] == 1
            ];
        } else {
            return [
                'valid' => false,
                'tag_data' => null,
                'saldo_suficiente' => false,
                'access_granted' => false
            ];
        }
    }

    /**
     * Procesa un evento de acceso y toma acciones automáticas
     * @param int $device_id
     * @param array $event_data
     * @return array
     */
    public function process_access_event($device_id, $event_data) {
        $card_no = $event_data['card_no'];
        $door_id = $event_data['door_id'];
        
        // Validar TAG
        $tag_validation = $this->validate_tag_access($card_no);
        
        if ($tag_validation['access_granted']) {
            // Si el acceso es válido y es la puerta 1 (lectura), abrir puerta 2 (barrera)
            if ($door_id == 1) {
                $open_result = $this->open_device_door($device_id, 2, "Acceso automático - TAG: {$card_no}");
                
                // Registrar movimiento
                $movement_data = [
                    'tag_id' => $tag_validation['tag_data']['id'],
                    'device_id' => $device_id,
                    'fecha_movimiento' => date('Y-m-d H:i:s', strtotime($event_data['event_time'])),
                    'tipo_movimiento' => 'ENTRADA',
                    'processed' => 1,
                    'isapi_event_id' => $event_data['event_id']
                ];
                
                $movement_id = $this->register_movement($movement_data);
                
                return [
                    'success' => true,
                    'action' => 'DOOR_OPENED',
                    'message' => 'Acceso concedido y barrera abierta',
                    'tag_data' => $tag_validation['tag_data'],
                    'movement_id' => $movement_id,
                    'door_result' => $open_result
                ];
            }
        } else {
            // Acceso denegado
            $this->log_access_denied($device_id, $card_no, $event_data);
            
            return [
                'success' => false,
                'action' => 'ACCESS_DENIED',
                'message' => 'Acceso denegado - TAG no válido o sin saldo',
                'tag_data' => $tag_validation['tag_data']
            ];
        }

        return [
            'success' => true,
            'action' => 'NO_ACTION',
            'message' => 'Evento procesado sin acciones adicionales'
        ];
    }

    // ================== MÉTODOS PRIVADOS DE APOYO ==================

    /**
     * Procesa y almacena eventos en la base de datos
     */
    private function _process_and_store_events($device_id, $events) {
        $processed_events = [];
        
        foreach ($events as $event) {
            // Verificar si el evento ya existe
            if (!$this->_event_exists($event['event_id'])) {
                $processed_event = $this->process_access_event($device_id, $event);
                $processed_events[] = array_merge($event, $processed_event);
            }
        }
        
        return $processed_events;
    }

    /**
     * Verifica si un evento ya existe en la base de datos
     */
    private function _event_exists($event_id) {
        $this->db->where('isapi_event_id', $event_id);
        $query = $this->db->get($this->movements_table);
        return $query->num_rows() > 0;
    }

    /**
     * Verifica el saldo de un TAG
     */
    private function _check_tag_balance($tag_id) {
        // Implementar lógica de verificación de saldo según tu sistema
        // Por ahora retorna true, pero debes implementar la lógica real
        return true;
    }

    /**
     * Actualiza el estado de conexión de un dispositivo
     */
    public function update_device_connection_status($device_id, $status) {
        $data = [
            'connection_status' => $status,
            'last_connection_check' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s')
        ];
        
        $this->db->where('id', $device_id);
        return $this->db->update($this->devices_table, $data);
    }

    /**
     * Registra acciones en puertas
     */
    public function log_door_action($device_id, $door_id, $action, $description) {
        $data = [
            'device_id' => $device_id,
            'door_id' => $door_id,
            'action' => $action,
            'description' => $description,
            'timestamp' => date('Y-m-d H:i:s'),
            'created_at' => date('Y-m-d H:i:s')
        ];
        
        return $this->db->insert($this->access_logs_table, $data);
    }

    /**
     * Registra accesos denegados
     */
    public function log_access_denied($device_id, $card_no, $event_data) {
        $data = [
            'device_id' => $device_id,
            'card_no' => $card_no,
            'event_data' => json_encode($event_data),
            'reason' => 'TAG no válido o sin saldo',
            'timestamp' => date('Y-m-d H:i:s'),
            'created_at' => date('Y-m-d H:i:s')
        ];
        
        return $this->db->insert('hikvision_access_denied', $data);
    }
}