<?php
class TrainingOrder
{
    public static function request(int $beginnerId, int $contentId): array
    {
        Database::migrate();
        $content = TrainingContent::find($contentId);
        if (!$content || empty($content['is_active'])) {
            return ['ok' => false, 'message' => 'Conteúdo indisponível.'];
        }
        try {
            $stmt = Database::pdo()->prepare("INSERT INTO training_orders (beginner_id, content_id, amount, status, created_at) VALUES (?, ?, ?, 'pending', ?)");
            $stmt->execute([$beginnerId, $contentId, (float)$content['price'], date('Y-m-d H:i:s')]);
            return ['ok' => true, 'message' => 'Solicitação enviada. Aguarde a cobrança ou liberação do administrador.'];
        } catch (PDOException $e) {
            return ['ok' => false, 'message' => 'Você já solicitou este conteúdo. Acompanhe o status abaixo.'];
        }
    }

    public static function forBeginner(int $beginnerId): array
    {
        Database::migrate();
        $stmt = Database::pdo()->prepare('SELECT o.*, c.title, c.description, c.content_type, c.file_path, c.video_url, c.original_name, c.mime_type, c.cover_path, c.cover_mime_type, c.is_active FROM training_orders o INNER JOIN training_contents c ON c.id = o.content_id WHERE o.beginner_id = ? ORDER BY o.created_at DESC');
        $stmt->execute([$beginnerId]);
        return $stmt->fetchAll();
    }

    public static function all(): array
    {
        Database::migrate();
        return Database::pdo()->query('SELECT o.*, b.name AS beginner_name, b.email AS beginner_email, b.whatsapp AS beginner_whatsapp, c.title AS content_title, c.content_type FROM training_orders o INNER JOIN beginner_instructors b ON b.id = o.beginner_id INNER JOIN training_contents c ON c.id = o.content_id ORDER BY CASE o.status WHEN \'proof_sent\' THEN 1 WHEN \'pending\' THEN 2 WHEN \'awaiting_payment\' THEN 3 ELSE 4 END, o.created_at DESC')->fetchAll();
    }

    public static function saveCharge(array $data): array
    {
        Database::migrate();
        $beginnerId = (int)($data['beginner_id'] ?? 0);
        $contentId = (int)($data['content_id'] ?? 0);
        $amount = parse_money_br($data['amount'] ?? '0');
        if ($beginnerId <= 0 || $contentId <= 0) {
            return ['ok' => false, 'message' => 'Selecione o instrutor em aprendizado e o conteúdo.'];
        }
        $initialStatus = trim((string)($data['initial_status'] ?? 'awaiting_payment'));
        if (!in_array($initialStatus, ['awaiting_payment', 'granted'], true)) {
            return ['ok' => false, 'message' => 'Selecione uma ação válida para o conteúdo.'];
        }
        $paymentLink = trim((string)($data['payment_link'] ?? ''));
        if ($initialStatus === 'awaiting_payment' && $paymentLink !== '' && !is_valid_http_url($paymentLink)) {
            return ['ok' => false, 'message' => 'Informe um link HTTP ou HTTPS válido para a cobrança.'];
        }
        if (!BeginnerInstructor::find($beginnerId) || !TrainingContent::find($contentId)) {
            return ['ok' => false, 'message' => 'Instrutor em aprendizado ou conteúdo não encontrado.'];
        }
        $existing = Database::pdo()->prepare('SELECT id FROM training_orders WHERE beginner_id = ? AND content_id = ? LIMIT 1');
        $existing->execute([$beginnerId, $contentId]);
        $orderId = (int)($existing->fetchColumn() ?: 0);
        $approvedAt = $initialStatus === 'granted' ? date('Y-m-d H:i:s') : null;
        if ($orderId > 0) {
            $stmt = Database::pdo()->prepare('UPDATE training_orders SET amount = ?, status = ?, payment_link = ?, pix_code = ?, admin_message = ?, approved_at = ? WHERE id = ?');
            $stmt->execute([$amount, $initialStatus, $paymentLink, trim((string)($data['pix_code'] ?? '')), trim((string)($data['admin_message'] ?? '')), $approvedAt, $orderId]);
        } else {
            $stmt = Database::pdo()->prepare('INSERT INTO training_orders (beginner_id, content_id, amount, status, payment_link, pix_code, admin_message, approved_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)');
            $stmt->execute([$beginnerId, $contentId, $amount, $initialStatus, $paymentLink, trim((string)($data['pix_code'] ?? '')), trim((string)($data['admin_message'] ?? '')), $approvedAt, date('Y-m-d H:i:s')]);
        }
        return ['ok' => true, 'message' => $initialStatus === 'granted' ? 'Conteúdo liberado diretamente para o instrutor e aprendizado.' : 'Cobrança enviada para a área do instrutor em aprendizado.'];
    }

    public static function submitProof(int $beginnerId, int $orderId, array $file): array
    {
        Database::migrate();
        $stmt = Database::pdo()->prepare("SELECT * FROM training_orders WHERE id = ? AND beginner_id = ? AND status IN ('pending','awaiting_payment','rejected') LIMIT 1");
        $stmt->execute([$orderId, $beginnerId]);
        $order = $stmt->fetch();
        if (!$order) {
            return ['ok' => false, 'message' => 'Cobrança não encontrada ou já liberada.'];
        }
        if (($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
            return ['ok' => false, 'message' => 'Selecione a imagem ou PDF do comprovante.'];
        }
        $size = (int)($file['size'] ?? 0);
        if ($size <= 0 || $size > 8 * 1024 * 1024) {
            return ['ok' => false, 'message' => 'O comprovante deve ter no máximo 8 MB.'];
        }
        $finfo = new finfo(FILEINFO_MIME_TYPE);
        $mime = (string)$finfo->file($file['tmp_name']);
        $allowed = ['application/pdf' => 'pdf', 'image/jpeg' => 'jpg', 'image/png' => 'png', 'image/webp' => 'webp'];
        if (!isset($allowed[$mime])) {
            return ['ok' => false, 'message' => 'Comprovante inválido. Use PDF, JPG, PNG ou WEBP.'];
        }
        $dir = STORAGE_PATH . '/training_proofs';
        if (!is_dir($dir)) {
            mkdir($dir, 0775, true);
        }
        $filename = bin2hex(random_bytes(20)) . '.' . $allowed[$mime];
        if (!move_uploaded_file($file['tmp_name'], $dir . '/' . $filename)) {
            return ['ok' => false, 'message' => 'Falha ao enviar o comprovante.'];
        }
        if (!empty($order['proof_path'])) {
            $old = ROOT_PATH . '/' . ltrim($order['proof_path'], '/');
            if (is_file($old)) {
                @unlink($old);
            }
        }
        $update = Database::pdo()->prepare("UPDATE training_orders SET status = 'proof_sent', proof_path = ?, proof_original_name = ?, proof_mime_type = ?, proof_submitted_at = ? WHERE id = ? AND beginner_id = ?");
        $update->execute(['storage/training_proofs/' . $filename, basename((string)($file['name'] ?? $filename)), $mime, date('Y-m-d H:i:s'), $orderId, $beginnerId]);
        return ['ok' => true, 'message' => 'Comprovante enviado. Aguarde a confirmação do administrador.'];
    }

    public static function updateStatus(int $orderId, string $status, string $message = ''): array
    {
        Database::migrate();
        if (!in_array($status, ['awaiting_payment', 'approved', 'granted', 'rejected'], true)) {
            return ['ok' => false, 'message' => 'Status inválido.'];
        }
        $exists = Database::pdo()->prepare('SELECT id FROM training_orders WHERE id = ? LIMIT 1');
        $exists->execute([$orderId]);
        if (!$exists->fetchColumn()) {
            return ['ok' => false, 'message' => 'Solicitação não encontrada.'];
        }
        $approvedAt = in_array($status, ['approved', 'granted'], true) ? date('Y-m-d H:i:s') : null;
        $stmt = Database::pdo()->prepare('UPDATE training_orders SET status = ?, admin_message = ?, approved_at = ? WHERE id = ?');
        $stmt->execute([$status, trim($message), $approvedAt, $orderId]);
        return ['ok' => true, 'message' => 'Situação do conteúdo atualizada.'];
    }

    public static function accessibleContent(int $beginnerId, int $contentId): ?array
    {
        Database::migrate();
        $stmt = Database::pdo()->prepare("SELECT c.* FROM training_orders o INNER JOIN training_contents c ON c.id = o.content_id WHERE o.beginner_id = ? AND o.content_id = ? AND o.status IN ('approved','granted') LIMIT 1");
        $stmt->execute([$beginnerId, $contentId]);
        $row = $stmt->fetch();
        return $row ?: null;
    }

    public static function proofForAdmin(int $orderId): ?array
    {
        Database::migrate();
        $stmt = Database::pdo()->prepare('SELECT * FROM training_orders WHERE id = ? AND proof_path IS NOT NULL LIMIT 1');
        $stmt->execute([$orderId]);
        $row = $stmt->fetch();
        return $row ?: null;
    }

    public static function streamProof(array $order): never
    {
        $path = ROOT_PATH . '/' . ltrim((string)($order['proof_path'] ?? ''), '/');
        if (!is_file($path)) {
            http_response_code(404);
            exit('Comprovante não encontrado.');
        }
        header('Content-Type: ' . (($order['proof_mime_type'] ?? '') ?: 'application/octet-stream'));
        header('Content-Length: ' . filesize($path));
        header('Content-Disposition: inline; filename="' . str_replace('"', '', (string)($order['proof_original_name'] ?? basename($path))) . '"');
        readfile($path);
        exit;
    }
}
