<?php
namespace EasyChat\Library\Operator;

use EasyChat\Library\ImageHelper;
use EasyChat\Library\SafeRuntime;
use EasyChat\Model\Manager;

final class OperatorAvatarService {
    public const MAX_FILE_SIZE = 5242880;
    private const MAX_DIMENSION = 12000;
    private const MAX_PIXELS = 24000000;

    private $registry;

    public function __construct($registry) {
        $this->registry = $registry;
    }

     
    public function upload(int $manager_id, array $file): array {
        $manager = (new Manager($this->registry))->getManagerById($manager_id);
        if (!$manager) {
            return $this->error('operator_not_found', 'Оператор не найден.');
        }
        if ((int)($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
            return $this->error('upload_failed', 'Не удалось загрузить изображение.');
        }

        $tmp = (string)($file['tmp_name'] ?? '');
        $size = (int)($file['size'] ?? 0);
        if ($tmp === '' || !is_uploaded_file($tmp) || $size <= 0) {
            return $this->error('upload_invalid', 'Загруженный файл недоступен.');
        }
        if ($size > self::MAX_FILE_SIZE) {
            return $this->error('upload_too_large', 'Максимальный размер фотографии — 5 МБ.');
        }

        $mime = $this->mime($tmp);
        if (!in_array($mime, ['image/jpeg', 'image/png', 'image/gif'], true)) {
            return $this->error('upload_type_invalid', 'Выберите изображение JPG, PNG или GIF.');
        }
        $info = SafeRuntime::imageInfo($tmp);
        $width = is_array($info) ? (int)($info[0] ?? 0) : 0;
        $height = is_array($info) ? (int)($info[1] ?? 0) : 0;
        $signature_mime = is_array($info) ? (string)($info['mime'] ?? '') : '';
        if ($width <= 0 || $height <= 0 || $signature_mime !== $mime
            || $width > self::MAX_DIMENSION || $height > self::MAX_DIMENSION
            || ($width * $height) > self::MAX_PIXELS
        ) {
            return $this->error('upload_image_invalid', 'Изображение повреждено или имеет слишком большое разрешение.');
        }

         
         
         
        if (!is_dir(DIR_AVATARS) && !mkdir(DIR_AVATARS, 0755, true) && !is_dir(DIR_AVATARS)) {
            return $this->error('avatar_storage_unavailable', 'Хранилище фотографий недоступно.');
        }

        $extension = [
            'image/jpeg' => 'jpg',
            'image/png' => 'png',
            'image/gif' => 'gif',
        ][$mime];
        $stem = 'avatar_' . $manager_id . '_' . bin2hex(random_bytes(10));
        $source = DIR_AVATARS . $stem . '.upload';
         
         
         
        $filename = $stem . '.' . $extension;
        $destination = DIR_AVATARS . $filename;
        if (!move_uploaded_file($tmp, $source)) {
            return $this->error('avatar_store_failed', 'Не удалось безопасно сохранить фотографию.');
        }

        try {
            if (!ImageHelper::resize($source, $destination, 300, 300, true)) {
                return $this->error('avatar_processing_failed', 'Не удалось обработать фотографию.');
            }
            @chmod($destination, 0644);

            $model = new Manager($this->registry);
            $old = (string)$model->getAvatar($manager_id);
            $model->updateAvatar($manager_id, $filename);
            if ($old !== '' && $old !== $filename) {
                $this->deleteKnownFile($old);
            }

            $version = substr(hash_file('sha256', $destination), 0, 16);
            return [
                'success' => true,
                'filename' => $filename,
                'url' => HTTP_AVATARS . rawurlencode($filename) . '?v=' . $version,
                'version' => $version,
            ];
        } catch (\Throwable $e) {
            SafeRuntime::unlink($destination);
            return $this->error('avatar_store_failed', 'Не удалось обновить фотографию.');
        } finally {
            SafeRuntime::unlink($source);
        }
    }

     
    public function remove(int $manager_id): array {
        $model = new Manager($this->registry);
        if (!$model->getManagerById($manager_id)) {
            return $this->error('operator_not_found', 'Оператор не найден.');
        }
        $old = (string)$model->getAvatar($manager_id);
        $model->updateAvatar($manager_id, '');
        if ($old !== '') {
            $this->deleteKnownFile($old);
        }
        return ['success' => true];
    }

     
    private function error(string $code, string $message): array {
        return ['success' => false, 'code' => $code, 'error' => $message];
    }

    private function mime(string $file): string {
        if (class_exists('\\finfo')) {
            return (string)(new \finfo(FILEINFO_MIME_TYPE))->file($file);
        }
        return function_exists('mime_content_type') ? (string)mime_content_type($file) : '';
    }

    private function deleteKnownFile(string $filename): void {
        $filename = basename($filename);
        if (preg_match('/^avatar_[a-zA-Z0-9_.-]+$/D', $filename) !== 1) {
            return;
        }
        $path = DIR_AVATARS . $filename;
        if (is_file($path)) {
            SafeRuntime::unlink($path);
        }
    }
}
