<?php
namespace EasyChat\Library;

require_once __DIR__ . '/attachment/office_document_inspector.php';

use EasyChat\Library\Attachment\OfficeDocumentInspector;









class AttachmentPolicy {

    public static function allowedImageExtensions(bool $include_webp = true): array {
        $extensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp'];
        if ($include_webp) {
            $extensions[] = 'webp';
        }
        return $extensions;
    }

    public static function maxMessengerImageExtensions(): array {
        return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'];
    }

    public static function allowedImageMimes(bool $include_webp = true): array {
        $mimes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/x-ms-bmp'];
        if ($include_webp) {
            $mimes[] = 'image/webp';
        }
        return $mimes;
    }

    public static function allowedDocumentExtensions(): array {
        return OfficeDocumentInspector::extensions();
    }

    public static function allowedDocumentMimes(): array {
        return OfficeDocumentInspector::mimes();
    }

    public static function allowedAudioExtensions(): array {
        return ['ogg', 'oga', 'opus', 'mp3', 'm4a', 'aac', 'wav', 'webm'];
    }

    public static function allowedAudioMimes(): array {
        return [
            'audio/ogg',
            'application/ogg',
            'audio/opus',
            'audio/mpeg',
            'audio/mp3',
            'audio/mp4',
            'audio/x-m4a',
            'audio/aac',
            'audio/x-aac',
            'audio/wav',
            'audio/x-wav',
            'audio/wave',
            'audio/webm',
            'video/webm',
        ];
    }

    public static function allowedAttachmentExtensions(bool $include_webp = true): array {
        return array_values(array_unique(array_merge(
            self::allowedImageExtensions($include_webp),
            self::allowedDocumentExtensions()
        )));
    }

    public static function mimeForExtension(string $extension): string {
        $extension = strtolower(trim($extension));
        $map = [
            'jpg'  => 'image/jpeg',
            'jpeg' => 'image/jpeg',
            'png'  => 'image/png',
            'gif'  => 'image/gif',
            'bmp'  => 'image/bmp',
            'webp' => 'image/webp',
            'ogg'  => 'audio/ogg',
            'oga'  => 'audio/ogg',
            'opus' => 'audio/ogg',
            'mp3'  => 'audio/mpeg',
            'm4a'  => 'audio/mp4',
            'aac'  => 'audio/aac',
            'wav'  => 'audio/wav',
            'webm' => 'audio/webm',
        ];
        if (in_array($extension, OfficeDocumentInspector::extensions(), true)) {
            return OfficeDocumentInspector::canonicalMime($extension);
        }
        return $map[$extension] ?? 'application/octet-stream';
    }

    public static function extensionForMime(string $mime): string {
        $mime = strtolower(trim($mime));
        $map = [
            'image/jpeg'    => 'jpg',
            'image/png'     => 'png',
            'image/gif'     => 'gif',
            'image/bmp'     => 'bmp',
            'image/x-ms-bmp'=> 'bmp',
            'image/webp'    => 'webp',
            'audio/ogg'     => 'ogg',
            'application/ogg' => 'ogg',
            'audio/opus'    => 'opus',
            'audio/mpeg'    => 'mp3',
            'audio/mp3'     => 'mp3',
            'audio/mp4'     => 'm4a',
            'audio/x-m4a'   => 'm4a',
            'audio/aac'     => 'aac',
            'audio/x-aac'   => 'aac',
            'audio/wav'     => 'wav',
            'audio/x-wav'   => 'wav',
            'audio/wave'    => 'wav',
            'audio/webm'    => 'webm',
            'video/webm'    => 'webm',
        ];
        return $map[$mime] ?? OfficeDocumentInspector::extensionForMime($mime);
    }

    public static function detectMime(string $path, string $fallback_extension = ''): string {
        if (is_file($path) && function_exists('mime_content_type')) {
            $mime = mime_content_type($path);
            if (is_string($mime) && $mime !== '') {
                return strtolower($mime);
            }
        }
        return self::mimeForExtension($fallback_extension);
    }

    public static function isImageExtension(string $extension, bool $include_webp = true): bool {
        return in_array(strtolower(trim($extension)), self::allowedImageExtensions($include_webp), true);
    }

    public static function isImageMime(string $mime, bool $include_webp = true): bool {
        return in_array(strtolower(trim($mime)), self::allowedImageMimes($include_webp), true);
    }

    public static function isDocumentExtension(string $extension): bool {
        return in_array(strtolower(trim($extension)), self::allowedDocumentExtensions(), true);
    }

    public static function isDocumentMime(string $mime): bool {
        return in_array(strtolower(trim($mime)), self::allowedDocumentMimes(), true);
    }

    public static function isAudioExtension(string $extension): bool {
        return in_array(strtolower(ltrim(trim($extension), '.')), self::allowedAudioExtensions(), true);
    }

    public static function isAudioMime(string $mime): bool {
        return in_array(strtolower(trim(explode(';', $mime)[0])), self::allowedAudioMimes(), true);
    }

    public static function isPdfFile(string $path): bool {
        return OfficeDocumentInspector::isPdf($path);
    }

    public static function isPdfExtension(string $extension): bool {
        return strtolower(ltrim(trim($extension), '.')) === 'pdf';
    }

    public static function documentFormatLabel(string $extension): string {
        return OfficeDocumentInspector::label($extension);
    }

    public static function validateImageFile(string $path, string $original_name, int $size, int $max_mb, bool $include_webp = true): array {
        $extension = strtolower(pathinfo($original_name, PATHINFO_EXTENSION));
        if (!in_array($extension, self::allowedImageExtensions($include_webp), true)) {
            return ['success' => false, 'error' => 'file_extension_denied'];
        }

        $max_bytes = max(1, $max_mb) * 1024 * 1024;
        if ($size <= 0 || $size > $max_bytes) {
            return ['success' => false, 'error' => 'file_size_denied'];
        }

        $mime = self::detectMime($path, $extension);
        if (!in_array($mime, self::allowedImageMimes($include_webp), true)) {
            return ['success' => false, 'error' => 'file_mime_denied'];
        }

        return [
            'success' => true,
            'kind' => 'image',
            'extension' => $extension,
            'mime' => $mime,
            'size' => $size,
        ];
    }

    public static function validateDocumentFile(string $path, string $original_name, int $size, int $max_mb): array {
        $extension = strtolower(pathinfo($original_name, PATHINFO_EXTENSION));
        if (!self::isDocumentExtension($extension)) {
            return ['success' => false, 'error' => 'file_extension_denied'];
        }

        $max_bytes = max(1, $max_mb) * 1024 * 1024;
        if ($size <= 0 || $size > $max_bytes) {
            return ['success' => false, 'error' => 'file_size_denied'];
        }

         
         
         
         
        $inspection = OfficeDocumentInspector::inspect($path, $extension);
        if (empty($inspection['success'])) {
            return ['success' => false, 'error' => (string)($inspection['error'] ?? 'file_mime_denied')];
        }

        return [
            'success' => true,
            'kind' => 'document',
            'extension' => (string)$inspection['extension'],
            'mime' => (string)$inspection['mime'],
            'format_label' => (string)$inspection['label'],
            'size' => $size,
        ];
    }

    public static function validateAudioFile(string $path, string $original_name, int $size, int $max_mb): array {
        $extension = strtolower(pathinfo($original_name, PATHINFO_EXTENSION));
        if (!self::isAudioExtension($extension)) {
            return ['success' => false, 'error' => 'file_extension_denied'];
        }

        $max_bytes = max(1, $max_mb) * 1024 * 1024;
        if ($size <= 0 || $size > $max_bytes) {
            return ['success' => false, 'error' => 'file_size_denied'];
        }

        $mime = self::detectMime($path, $extension);
        if (!self::isAudioMime($mime)) {
            return ['success' => false, 'error' => 'file_mime_denied'];
        }

        if (!self::hasAudioContainerSignature($path, $extension)) {
            return ['success' => false, 'error' => 'file_container_denied'];
        }

        return [
            'success' => true,
            'kind' => 'audio',
            'extension' => $extension,
            'mime' => self::canonicalAudioMime($extension, $mime),
            'size' => $size,
        ];
    }

    public static function validateAttachmentFile(string $path, string $original_name, int $size, int $max_mb, bool $include_webp = true): array {
        $extension = strtolower(pathinfo($original_name, PATHINFO_EXTENSION));
        if (self::isImageExtension($extension, $include_webp)) {
            return self::validateImageFile($path, $original_name, $size, $max_mb, $include_webp);
        }
        if (self::isDocumentExtension($extension)) {
            return self::validateDocumentFile($path, $original_name, $size, $max_mb);
        }
        if (self::isAudioExtension($extension)) {
            return self::validateAudioFile($path, $original_name, $size, $max_mb);
        }
        return ['success' => false, 'error' => 'file_extension_denied'];
    }

    private static function canonicalAudioMime(string $extension, string $detected_mime): string {
        $canonical = self::mimeForExtension($extension);
        return $canonical !== 'application/octet-stream' ? $canonical : strtolower(trim($detected_mime));
    }

    



    private static function hasAudioContainerSignature(string $path, string $extension): bool {
        $handle = @fopen($path, 'rb');
        if ($handle === false) {
            return false;
        }
        $head = (string)fread($handle, 64);
        fclose($handle);
        if ($head === '') {
            return false;
        }

        if (in_array($extension, ['ogg', 'oga', 'opus'], true)) {
            return substr($head, 0, 4) === 'OggS';
        }
        if ($extension === 'wav') {
            return substr($head, 0, 4) === 'RIFF' && substr($head, 8, 4) === 'WAVE';
        }
        if ($extension === 'm4a') {
            return strlen($head) >= 12 && substr($head, 4, 4) === 'ftyp';
        }
        if ($extension === 'webm') {
            return substr($head, 0, 4) === "\x1A\x45\xDF\xA3";
        }
        if ($extension === 'mp3') {
            return substr($head, 0, 3) === 'ID3'
                || (strlen($head) >= 2 && ord($head[0]) === 0xFF && (ord($head[1]) & 0xE0) === 0xE0);
        }
        if ($extension === 'aac') {
            return strlen($head) >= 2 && ord($head[0]) === 0xFF && (ord($head[1]) & 0xF6) === 0xF0;
        }
        return false;
    }

    public static function isMaxImageExtension(string $extension): bool {
        return in_array(strtolower($extension), self::maxMessengerImageExtensions(), true);
    }
}
