<?php

namespace App\Helpers\Formats;

class AddressFormatterHelper
{
    /**
     * Ensambla una dirección en una sola línea, omitiendo campos vacíos.
     * Neutral para cualquier país; puedes ajustar etiquetas con $opts.
     *
     * Keys esperadas en $addr:
     *  - street, exterior, interior
     *  - neighborhood, city, municipality
     *  - state, zip, country
     *
     * $opts disponibles:
     *  - ext_label (string)  p.ej. 'No.' o '#'
     *  - int_label (string)  p.ej. 'Int.' / 'Apt' / 'Suite' (default: 'Unit')
     *  - zip_label (string)  p.ej. 'CP' (MX), 'ZIP' (US); vacío = neutral
     *  - unit_sep  (string)  separador entre etiqueta y número (default: ' ')
     */
    public static function format(array $addr, array $opts = []): string
    {
        $addr = self::normalizeMexicanAddress($addr);

        $get = static function (string $key) use ($addr) {
            $v = $addr[$key] ?? null;
            if (is_string($v)) {
                $v = trim($v);
            }
            return ($v === '' ? null : $v);
        };

        $extLabel = $opts['ext_label']  ?? '';
        $intLabel = $opts['int_label']  ?? 'Unit';
        $zipLabel = $opts['zip_label']  ?? '';
        $unitSep  = $opts['unit_sep']   ?? ' ';

        // 1) Vía
        $street = $get('street');
        $ext    = $get('exterior');
        $int    = $get('interior');

        $via = null;
        if ($street || $ext || $int) {
            $parts = [];
            if ($street) { $parts[] = $street; }
            if ($ext)    { $parts[] = ($extLabel ? ($extLabel . $unitSep) : '') . $ext; }
            if ($int)    { $parts[] = ($intLabel ? ($intLabel . $unitSep) : '') . $int; }
            $via = preg_replace('/\s+/', ' ', implode(' ', $parts));
        }

        // 2) Localidad
        $neigh = $get('neighborhood');
        $city  = $get('city');
        $mun   = $get('municipality');
        $state = $get('state');

        // Evitar duplicado city/municipality si son iguales
        if ($city && $mun && mb_strtolower($city) === mb_strtolower($mun)) {
            $mun = null;
        }

        $localParts = array_values(array_filter([$neigh, $city, $mun, $state], static fn($v) => !is_null($v)));

        // 3) ZIP
        $zip = $get('zip');
        $zipPart = $zip ? trim(($zipLabel ? "$zipLabel " : '') . $zip) : null;

        // 4) País
        $country = $get('country') ?? 'MEX';
        $country = mb_strtoupper(__("countries.$country"));

        // 5) Unir todo
        $full = array_values(array_filter([$via, ...$localParts, $country, $zipPart], static fn($v) => !is_null($v)));
        $oneLine = implode(', ', $full);

        // Limpiezas menores
        $oneLine = preg_replace('/\s+,/',' ,', $oneLine);
        $oneLine = preg_replace('/\s+/', ' ', $oneLine);
        $oneLine = trim($oneLine);

        // Si todo vacío, al menos regresa el ZIP si existe
        return $oneLine !== '' ? $oneLine : ($zip ?? '');
    }

    /**
     *  Normaliza direcciones mexicanas antes de ser formateadas.
     *
     *  @param array $addr Address structure
     *  @return array
     */
    private static function normalizeMexicanAddress(array $addr): array
    {
        $country = $addr['country'] ?? null;

        // Solo aplicar lógica especial para México
        if (!$country || mb_strtoupper($country) !== 'MEX')
            return $addr;

        $street = $addr['street'] ?? null;
        $int    = $addr['interior'] ?? null;
        $neigh  = $addr['neighborhood'] ?? null;

        if ($int) {
            $intUpper = mb_strtoupper($int);

            // Detectar patrones catastrales mexicanos (NO son interiores reales)
            $looksLikePlot = preg_match('/\b(MZA|MANZANA|LT|LOTE)\b/u', $intUpper);

            if ($looksLikePlot) {
                $street = trim(($street ?? '') . ' ' . $int);
                $addr['street'] = $street;
                $addr['interior'] = null;
            }
        }

        // Si neighborhood ya viene incluido en street, evitar duplicarlo
        if ($neigh && $street) {
            if (str_contains(
                mb_strtoupper($street), mb_strtoupper($neigh)
            )) {
                $addr['neighborhood'] = null;
            }
        }

        return $addr;
    }

}
