<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class SecureUpload implements Rule
{
    private $message = 'Arquivo inválido.';

    public function passes($attribute, $file)
    {
        if (!$file instanceof \Illuminate\Http\UploadedFile) {
            $this->message = 'Nenhum arquivo enviado.';
            return false;
        }

        // MIME REAL (seguro)
        $mime = $file->getMimeType();

        // Extensões MIME permitidas
        $allowed = [
            // IMAGENS
            'image/jpeg',
            'image/png',
            'image/gif',
            'image/webp',
            'image/svg+xml',

            // DOCUMENTOS
            'application/pdf',
            'application/msword', // .doc
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
            'application/vnd.ms-excel', // .xls
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
        ];

        if (!in_array($mime, $allowed)) {
            $this->message = "Tipo de arquivo não permitido: {$mime}";
            return false;
        }

        // Conteúdo do arquivo
        $contents = file_get_contents($file->getRealPath());

        // Bloqueia PHP escondido dentro de qualquer arquivo
        if (preg_match('/<\?(php|=)|eval\(|base64_decode\(/i', $contents)) {
            $this->message = 'Arquivo inválido.';
            return false;
        }

        // Validação específica por MIME
        if (strpos($mime, 'image/') === 0) {
            return $this->validateImage($mime, $contents, $file);
        }

        return $this->validateDocument($mime, $contents);
    }

    /* --------------------- VALIDAR IMAGENS ---------------------- */
    private function validateImage($mime, $contents, $file)
    {
        // SVG
        if ($mime === 'image/svg+xml') {
            return $this->validateSvg($contents);
        }

        // WEBP – bloquear animado
        if ($mime === 'image/webp') {
            if (strpos($contents, 'ANIM') !== false) {
                $this->message = 'WebP animado não é permitido.';
                return false;
            }
        }

        // RASTER (jpg/png/gif/webp simples)
        $info = @getimagesize($file->getRealPath());
        if (!$info) {
            $this->message = 'Imagem inválida ou corrompida.';
            return false;
        }

        return true;
    }

    private function validateSvg($contents)
    {
        // Proibe scripts
        if (stripos($contents, '<script') !== false) {
            $this->message = 'SVG contém scripts e não é seguro.';
            return false;
        }

        // Proibe tags perigosas
        $dangerous = ['foreignObject', 'iframe', 'embed', 'object', 'audio', 'video'];
        foreach ($dangerous as $tag) {
            if (stripos($contents, "<$tag") !== false) {
                $this->message = "SVG contém elemento inseguro: <$tag>";
                return false;
            }
        }

        return true;
    }

    /* --------------------- VALIDAR DOCUMENTOS ---------------------- */
    private function validateDocument($mime, $contents)
    {
        switch ($mime) {
            case 'application/pdf':
                return $this->validatePdf($contents);

            case 'application/msword':
                return $this->validateDoc($contents);

            case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
            case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
            case 'application/vnd.ms-excel':
                return $this->validateOfficeFile($contents);

            default:
                $this->message = 'Tipo de documento inválido.';
                return false;
        }
    }

    private function validatePdf($contents)
    {
        // PDF deve começar com %PDF
        if (strpos($contents, '%PDF') !== 0) {
            $this->message = 'PDF inválido.';
            return false;
        }

        // Deve conter o final %%EOF
        if (strpos($contents, '%%EOF') === false) {
            $this->message = 'PDF incompleto ou corrompido.';
            return false;
        }

        return true;
    }

    private function validateDoc($contents)
    {
        // Arquivos .doc começam com D0 CF 11 E0 (header Ole Compound)
        if (substr($contents, 0, 8) !== "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1") {
            $this->message = 'Arquivo DOC inválido.';
            return false;
        }

        return true;
    }

    private function validateOfficeFile($contents)
    {
        // DOCX, XLSX são arquivos ZIP (PK\x03\x04)
        if (substr($contents, 0, 2) !== "PK") {
            $this->message = 'Arquivo Office inválido.';
            return false;
        }

        return true;
    }

    /* --------------------- MENSAGEM FINAL ---------------------- */
    public function message()
    {
        return $this->message;
    }
}