<?php
/**
 * OrdenMedica — Gestión de órdenes médicas recibidas por WhatsApp.
 *
 * Flujo de estados:
 *   pendiente → en_revision → autorizada → en_domicilio → completada
 *                           └→ rechazada
 */

require_once __DIR__ . '/../../classes/Database.php';
require_once __DIR__ . '/ActividadAdmin.php';

class OrdenMedica {

    // Estados válidos
    const ESTADOS = [
        'pendiente',
        'en_revision',
        'autorizada',
        'rechazada',
        'en_domicilio',
        'completada',
    ];

    private Database $db;
    private ActividadAdmin $log;

    public function __construct() {
        $this->db  = Database::getInstance();
        $this->log = new ActividadAdmin();
    }

    // ─────────────────────────────────────────────────────────────────────────
    // CRUD
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Lista paginada de órdenes con filtros.
     *
     * @param array $filtros  estado, paciente_id, desde, hasta, busqueda
     */
    public function listar(array $filtros = [], int $pagina = 1, int $porPagina = 30): array {
        $wheres = [];
        $params = [];

        if (!empty($filtros['estado'])) {
            $wheres[] = 'o.estado = ?';
            $params[] = $filtros['estado'];
        }
        if (!empty($filtros['paciente_id'])) {
            $wheres[] = 'o.paciente_id = ?';
            $params[] = $filtros['paciente_id'];
        }
        if (!empty($filtros['desde'])) {
            $wheres[] = 'DATE(o.created_at) >= ?';
            $params[] = $filtros['desde'];
        }
        if (!empty($filtros['hasta'])) {
            $wheres[] = 'DATE(o.created_at) <= ?';
            $params[] = $filtros['hasta'];
        }
        if (!empty($filtros['busqueda'])) {
            $like     = '%' . $filtros['busqueda'] . '%';
            $wheres[] = '(p.nombre_completo LIKE ? OR p.numero_documento LIKE ?)';
            $params[] = $like;
            $params[] = $like;
        }

        $where  = $wheres ? 'WHERE ' . implode(' AND ', $wheres) : '';
        $offset = ($pagina - 1) * $porPagina;

        $total = $this->db->fetch(
            "SELECT COUNT(*) AS n
             FROM   lab_ordenes_medicas o
             JOIN   lab_pacientes p ON p.id = o.paciente_id
             $where",
            $params
        )['n'] ?? 0;

        $rows = $this->db->fetchAll("
            SELECT
                o.*,
                p.nombre_completo AS paciente_nombre,
                p.numero_documento,
                p.telefono        AS paciente_telefono,
                rev.full_name     AS revisada_por_nombre,
                aut.full_name     AS autorizada_por_nombre
            FROM  lab_ordenes_medicas o
            JOIN  lab_pacientes  p   ON p.id  = o.paciente_id
            LEFT  JOIN admin_users rev ON rev.id = o.revisada_por
            LEFT  JOIN admin_users aut ON aut.id = o.autorizada_por
            $where
            ORDER BY o.created_at DESC
            LIMIT ? OFFSET ?
        ", array_merge($params, [$porPagina, $offset]));

        return [
            'data'       => $rows,
            'total'      => (int)$total,
            'pagina'     => $pagina,
            'por_pagina' => $porPagina,
            'paginas'    => (int)ceil($total / $porPagina),
        ];
    }

    /**
     * Obtener una orden por ID (con todos los datos relacionados).
     */
    public function obtener(int $id): ?array {
        $orden = $this->db->fetch("
            SELECT
                o.*,
                p.nombre_completo  AS paciente_nombre,
                p.numero_documento,
                p.telefono         AS paciente_telefono,
                p.eps              AS paciente_eps,
                p.user_id,
                u.phone_number,
                rev.full_name      AS revisada_por_nombre,
                aut.full_name      AS autorizada_por_nombre,
                c.local_file       AS conv_local_file,
                c.whatsapp_media_id AS conv_media_id
            FROM  lab_ordenes_medicas o
            JOIN  lab_pacientes  p   ON p.id  = o.paciente_id
            LEFT  JOIN users         u   ON u.id  = p.user_id
            LEFT  JOIN admin_users  rev ON rev.id = o.revisada_por
            LEFT  JOIN admin_users  aut ON aut.id = o.autorizada_por
            LEFT  JOIN conversations c  ON c.id   = o.conversation_id
            WHERE o.id = ?
        ", [$id]);

        if (!$orden) {
            return null;
        }

        // Historial de cambios de estado
        $orden['historial'] = $this->db->fetchAll("
            SELECT
                la.*,
                au.full_name AS admin_nombre
            FROM  lab_autorizaciones la
            LEFT  JOIN admin_users au ON au.id = la.realizada_por
            WHERE la.orden_id = ?
            ORDER BY la.created_at ASC
        ", [$id]);

        return $orden;
    }

    /**
     * Crear nueva orden médica.
     */
    public function crear(array $datos, ?int $adminId = null): int {
        $campos = $this->filtrarCampos($datos);
        $id     = $this->db->insert('lab_ordenes_medicas', $campos);

        // Registrar en historial
        $this->registrarCambioEstado($id, null, 'pendiente', $adminId, 'Orden creada', 'creada');
        $this->log->registrar($adminId, 'ordenes', 'crear', $id, $campos);

        return $id;
    }

    /**
     * Actualizar datos de la orden (sin cambiar estado).
     */
    public function actualizar(int $id, array $datos, ?int $adminId = null): bool {
        $campos = $this->filtrarCampos($datos);
        unset($campos['estado']); // el estado se cambia con cambiarEstado()
        $ok = $this->db->update('lab_ordenes_medicas', $campos, 'id = ?', [$id]);
        if ($ok) {
            $this->registrarCambioEstado($id, null, null, $adminId, 'Datos actualizados', 'editada');
            $this->log->registrar($adminId, 'ordenes', 'editar', $id, $campos);
        }
        return $ok > 0;
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Gestión de estados (flujo de revisión)
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Cambia el estado de la orden con trazabilidad completa.
     *
     * @param int    $id
     * @param string $nuevoEstado  Debe estar en self::ESTADOS
     * @param int    $adminId
     * @param string $comentario
     */
    public function cambiarEstado(
        int $id,
        string $nuevoEstado,
        int $adminId,
        string $comentario = ''
    ): bool {
        if (!in_array($nuevoEstado, self::ESTADOS)) {
            throw new InvalidArgumentException("Estado inválido: $nuevoEstado");
        }

        $orden = $this->obtener($id);
        if (!$orden) {
            throw new RuntimeException("Orden #$id no encontrada");
        }

        $estadoAnterior = $orden['estado'];
        $ahora          = date('Y-m-d H:i:s');

        $campos = ['estado' => $nuevoEstado];

        // Campos adicionales según el nuevo estado
        if ($nuevoEstado === 'en_revision') {
            $campos['revisada_por'] = $adminId;
            $campos['revisada_at']  = $ahora;
        } elseif (in_array($nuevoEstado, ['autorizada', 'rechazada'])) {
            $campos['autorizada_por']        = $adminId;
            $campos['autorizada_at']         = $ahora;
            $campos['comentario_revision']   = $comentario;
        }

        $ok = $this->db->update('lab_ordenes_medicas', $campos, 'id = ?', [$id]);

        if ($ok) {
            $this->registrarCambioEstado($id, $estadoAnterior, $nuevoEstado, $adminId, $comentario);
            $this->log->registrar($adminId, 'ordenes', $nuevoEstado, $id, [
                'estado_anterior' => $estadoAnterior,
                'comentario'      => $comentario,
            ]);
        }

        return $ok > 0;
    }

    // Alias de conveniencia
    public function autorizar(int $id, int $adminId, string $comentario = ''): bool {
        return $this->cambiarEstado($id, 'autorizada', $adminId, $comentario);
    }

    public function rechazar(int $id, int $adminId, string $motivo): bool {
        return $this->cambiarEstado($id, 'rechazada', $adminId, $motivo);
    }

    public function iniciarRevision(int $id, int $adminId): bool {
        return $this->cambiarEstado($id, 'en_revision', $adminId);
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Estadísticas / Dashboard
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Conteo de órdenes por estado.
     */
    public function contadorPorEstado(): array {
        $rows = $this->db->fetchAll("
            SELECT estado, COUNT(*) AS total
            FROM   lab_ordenes_medicas
            GROUP  BY estado
        ");
        $result = array_fill_keys(self::ESTADOS, 0);
        foreach ($rows as $row) {
            $result[$row['estado']] = (int)$row['total'];
        }
        return $result;
    }

    /**
     * Órdenes pendientes más antiguas (sin revisar).
     */
    public function pendientesAntiguos(int $limit = 10): array {
        return $this->db->fetchAll("
            SELECT
                o.*,
                p.nombre_completo,
                TIMESTAMPDIFF(HOUR, o.created_at, NOW()) AS horas_espera
            FROM  lab_ordenes_medicas o
            JOIN  lab_pacientes p ON p.id = o.paciente_id
            WHERE o.estado = 'pendiente'
            ORDER BY o.created_at ASC
            LIMIT ?
        ", [$limit]);
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Helpers privados
    // ─────────────────────────────────────────────────────────────────────────

    private function registrarCambioEstado(
        int $ordenId,
        ?string $estadoAnterior,
        ?string $estadoNuevo,
        ?int $adminId,
        string $comentario = '',
        string $accion = ''
    ): void {
        $accion = $accion ?: ($estadoNuevo ?? 'editada');
        $this->db->insert('lab_autorizaciones', [
            'orden_id'       => $ordenId,
            'accion'         => $accion,
            'estado_anterior'=> $estadoAnterior,
            'estado_nuevo'   => $estadoNuevo,
            'realizada_por'  => $adminId,
            'comentario'     => $comentario,
        ]);
    }

    private function filtrarCampos(array $datos): array {
        $permitidos = [
            'paciente_id', 'conversation_id', 'whatsapp_media_id', 'local_file',
            'domicilio_id', 'estado', 'medico_nombre', 'medico_registro', 'fecha_orden',
            'diagnostico', 'examenes_solicitados', 'requiere_ayuno',
            'horas_ayuno', 'indicaciones', 'revisada_por', 'revisada_at',
            'autorizada_por', 'autorizada_at', 'comentario_revision', 'notas_admin',
        ];
        return array_intersect_key($datos, array_flip($permitidos));
    }
}
