<?php

declare(strict_types=1);

namespace ImovelZapAi\Publishing\Application\Services;

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;
use ImovelZapAi\Properties\Application\Services\PropertyMediaUrlResolver;
use ImovelZapAi\Properties\Infrastructure\Persistence\Eloquent\PropertyImageModel;
use ImovelZapAi\Properties\Infrastructure\Persistence\Eloquent\PropertyModel;
use ImovelZapAi\Publishing\Application\Data\MediaProcessingResult;
use ImovelZapAi\Publishing\Application\Ports\MediaAccessibilityCheckerInterface;
use ImovelZapAi\Publishing\Domain\Canonical\NormalizedListingPhoto;

/**
 * Prepara mídia para feeds de portal — URLs públicas, válidas e acessíveis.
 */
final class MediaProcessor
{
    public function __construct(
        private readonly PropertyMediaUrlResolver $mediaUrlResolver,
        private readonly MediaAccessibilityCheckerInterface $accessibilityChecker,
    ) {}

    public function process(PropertyModel $property): MediaProcessingResult
    {
        $property->loadMissing('images');

        /** @var Collection<int, PropertyImageModel> $images */
        $images = $property->images
            ->sortBy([
                ['is_cover', 'desc'],
                ['order', 'asc'],
            ])
            ->values();

        $photos = [];
        $skipped = [];
        $maxImages = (int) config('publishing.media.max_images', 30);
        $checkAccessibility = (bool) config('publishing.media.check_accessibility', false);

        foreach ($images as $image) {
            if (count($photos) >= $maxImages) {
                $skipped[] = $this->skipReason($image, 'limite de imagens atingido');

                continue;
            }

            $validationError = $this->validateImage($image);

            if ($validationError !== null) {
                $skipped[] = $this->skipReason($image, $validationError);

                continue;
            }

            $url = $this->mediaUrlResolver->publicUrl($image);

            if ($url === null || trim($url) === '') {
                $skipped[] = $this->skipReason($image, 'URL pública indisponível');

                continue;
            }

            if ($checkAccessibility && ! $this->accessibilityChecker->isAccessible($url)) {
                $skipped[] = $this->skipReason($image, 'URL inacessível para portais');

                continue;
            }

            $photos[] = new NormalizedListingPhoto(
                url: $url,
                isPrimary: (bool) $image->is_cover || $photos === [],
                caption: $this->caption($image),
            );
        }

        if ($photos !== [] && ! collect($photos)->contains(fn (NormalizedListingPhoto $photo): bool => $photo->isPrimary)) {
            $photos[0] = new NormalizedListingPhoto(
                url: $photos[0]->url,
                isPrimary: true,
                caption: $photos[0]->caption,
            );
        }

        return new MediaProcessingResult(photos: $photos, skipped: $skipped);
    }

    private function validateImage(PropertyImageModel $image): ?string
    {
        if (trim((string) $image->path) === '') {
            return 'caminho vazio';
        }

        if (! $this->hasAllowedExtension((string) $image->path)) {
            return 'extensão não suportada';
        }

        if (! Storage::disk('public')->exists($image->path)) {
            return 'arquivo não encontrado';
        }

        $dimensions = $this->resolveDimensions($image->path);

        if ($dimensions === null) {
            return 'imagem inválida';
        }

        [$width, $height] = $dimensions;
        $minWidth = (int) config('publishing.media.min_width', 600);
        $minHeight = (int) config('publishing.media.min_height', 400);

        if ($width < $minWidth || $height < $minHeight) {
            return "resolução abaixo do mínimo ({$width}x{$height})";
        }

        return null;
    }

    private function hasAllowedExtension(string $path): bool
    {
        /** @var list<string> $allowed */
        $allowed = config('publishing.media.allowed_extensions', ['jpg', 'jpeg', 'png', 'webp']);
        $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));

        return in_array($extension, $allowed, true);
    }

    /**
     * @return array{0: int, 1: int}|null
     */
    private function resolveDimensions(string $path): ?array
    {
        $absolutePath = Storage::disk('public')->path($path);
        $info = @getimagesize($absolutePath);

        if ($info === false) {
            return null;
        }

        return [(int) $info[0], (int) $info[1]];
    }

    private function caption(PropertyImageModel $image): ?string
    {
        $caption = trim((string) ($image->caption ?? ''));

        return $caption !== '' ? $caption : null;
    }

    private function skipReason(PropertyImageModel $image, string $reason): string
    {
        return sprintf('image:%s — %s', (string) $image->id, $reason);
    }
}
