<?php

declare(strict_types=1);

namespace ImovelZapAi\Properties\Application\Services;

use ImovelZapAi\Properties\Application\Data\PropertyMapViewData;
use ImovelZapAi\Properties\Infrastructure\Persistence\Eloquent\PropertyModel;

final class PropertyMapPresenter
{
    public function present(PropertyModel $property): PropertyMapViewData
    {
        $query = $this->locationQuery($property);
        $apiKey = trim((string) config('google_maps.api_key', ''));
        $zoom = max(1, min(21, (int) config('google_maps.default_zoom', 15)));
        $embedDriver = strtolower(trim((string) config('google_maps.embed_driver', 'legacy')));

        if ($query === null) {
            return new PropertyMapViewData(
                hasLocation: false,
                embedUrl: null,
                externalUrl: null,
                coordinatesLabel: null,
                usesApiKey: $apiKey !== '',
            );
        }

        $useEmbedApi = $embedDriver === 'api' && $apiKey !== '';

        $embedUrl = $useEmbedApi
            ? $this->embedApiUrl($query, $apiKey, $zoom)
            : $this->legacyEmbedUrl($query, $zoom);

        return new PropertyMapViewData(
            hasLocation: true,
            embedUrl: $embedUrl,
            externalUrl: 'https://www.google.com/maps/search/?api=1&query='.rawurlencode($query),
            coordinatesLabel: $this->coordinatesLabel($property),
            usesApiKey: $apiKey !== '',
        );
    }

    private function locationQuery(PropertyModel $property): ?string
    {
        if ($property->latitude !== null && $property->longitude !== null) {
            return $this->formatCoordinate((string) $property->latitude)
                .','.$this->formatCoordinate((string) $property->longitude);
        }

        $street = trim((string) ($property->street ?? ''));
        $cep = trim((string) ($property->cep ?? ''));

        if ($street === '' && $cep === '') {
            return null;
        }

        $parts = array_filter([
            trim(implode(', ', array_filter([
                $street !== '' ? $street : null,
                $property->number,
            ], static fn (?string $part): bool => $part !== null && trim($part) !== ''))),
            $property->neighborhood?->name,
            $property->city?->name,
            $property->state?->code,
            $cep !== '' ? $cep : null,
            'Brasil',
        ], static fn (?string $part): bool => $part !== null && trim($part) !== '');

        if ($parts === []) {
            return null;
        }

        return implode(', ', $parts);
    }

    private function embedApiUrl(string $query, string $apiKey, int $zoom): string
    {
        return 'https://www.google.com/maps/embed/v1/place?'
            .http_build_query([
                'key' => $apiKey,
                'q' => $query,
                'zoom' => $zoom,
                'language' => 'pt-BR',
            ], '', '&', PHP_QUERY_RFC3986);
    }

    private function legacyEmbedUrl(string $query, int $zoom): string
    {
        return 'https://maps.google.com/maps?'
            .http_build_query([
                'q' => $query,
                'z' => $zoom,
                'hl' => 'pt-BR',
                'output' => 'embed',
            ], '', '&', PHP_QUERY_RFC3986);
    }

    private function coordinatesLabel(PropertyModel $property): ?string
    {
        if ($property->latitude === null || $property->longitude === null) {
            return null;
        }

        return $this->formatCoordinate((string) $property->latitude)
            .', '.$this->formatCoordinate((string) $property->longitude);
    }

    private function formatCoordinate(string $value): string
    {
        return number_format((float) $value, 7, '.', '');
    }
}
