<?php

namespace App\Domains\Event\Services;

use DateTimeImmutable;

class EventDateTextFormatter
{
    /** @var array<int, string> */
    private const MONTHS = [
        1 => 'Enero',
        2 => 'Febrero',
        3 => 'Marzo',
        4 => 'Abril',
        5 => 'Mayo',
        6 => 'Junio',
        7 => 'Julio',
        8 => 'Agosto',
        9 => 'Septiembre',
        10 => 'Octubre',
        11 => 'Noviembre',
        12 => 'Diciembre',
    ];

    /** @param iterable<string> $dates */
    public function format(iterable $dates): ?string
    {
        $normalizedDates = collect($dates)
            ->map(fn (string $date): DateTimeImmutable => new DateTimeImmutable($date))
            ->unique(fn (DateTimeImmutable $date): string => $date->format('Y-m-d'))
            ->sortBy(fn (DateTimeImmutable $date): string => $date->format('Y-m-d'))
            ->values();

        if ($normalizedDates->isEmpty()) {
            return null;
        }

        $years = $normalizedDates
            ->groupBy(fn (DateTimeImmutable $date): string => $date->format('Y'))
            ->map(function ($yearDates, string $year): string {
                $months = $yearDates
                    ->groupBy(fn (DateTimeImmutable $date): string => $date->format('n'))
                    ->map(function ($monthDates, string $month): string {
                        $days = $monthDates
                            ->map(fn (DateTimeImmutable $date): string => (string) ((int) $date->format('j')))
                            ->values()
                            ->all();

                        return $this->join($days).' de '.self::MONTHS[(int) $month];
                    })
                    ->values()
                    ->all();

                return $this->join($months).' '.$year;
            })
            ->values()
            ->all();

        return $this->join($years);
    }

    /** @param array<int, string> $parts */
    private function join(array $parts): string
    {
        if (count($parts) <= 1) {
            return $parts[0] ?? '';
        }

        $last = array_pop($parts);

        return implode(', ', $parts).' y '.$last;
    }
}
