<?php

declare(strict_types=1);

namespace App\Services\Supplier;

use App\Services\Supplier\Dto\SupplierProjectDto;
use Carbon\Carbon;
use Illuminate\Support\Collection;

/**
 * Pure function: распределение квоты daily_limit между platform B1/B2/B3.
 *
 * Используется SyncSupplierProjectsJob для агрегирования daily_limit_target
 * всех активных Лидерра-проектов на одного supplier_project и распределения
 * суммарной квоты между B1/B2/B3 платформами.
 *
 * Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §4.3-§4.4
 *
 * Distribution-формулы:
 *   site/call:
 *     B1 = ceil(total/3)
 *     B2 = ceil((total - B1) / 2)
 *     B3 = total - B1 - B2
 *   sms-with-keyword (B1 не поддерживает СМС):
 *     B1 = 0
 *     B2 = ceil(total/2)
 *     B3 = floor(total/2)
 *
 * Workdays и regions — союзы (deduplicated, sorted) активных Лидерра-проектов,
 * eligible на targetDate (фильтр по weekday в Europe/Moscow).
 */
final class SupplierQuotaAllocator
{
    /**
     * @param  Collection<int, \stdClass>  $activeLiderraProjects  объекты с полями daily_limit, workdays, regions
     */
    public static function allocate(
        string $platform,
        string $signalType,
        string $uniqueKey,
        Collection $activeLiderraProjects,
        Carbon $targetDate,
    ): ?SupplierProjectDto {
        $targetWeekday = $targetDate->copy()->timezone('Europe/Moscow')->isoWeekday();

        $eligibleProjects = $activeLiderraProjects->filter(
            fn (\stdClass $p) => in_array($targetWeekday, (array) $p->workdays, true)
        );

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

        $totalQuota = (int) $eligibleProjects->sum('daily_limit');
        $workdaysUnion = self::unionInts($eligibleProjects->pluck('workdays'));
        $regionsUnion = self::unionInts($eligibleProjects->pluck('regions'));

        $platformLimit = self::distributeForPlatform($signalType, $platform, $totalQuota);

        return new SupplierProjectDto(
            platform: $platform,
            signalType: $signalType,
            uniqueKey: $uniqueKey,
            limit: $platformLimit,
            workdays: $workdaysUnion,
            regions: $regionsUnion,
            regionsReverse: false,
            status: 'active',
        );
    }

    private static function distributeForPlatform(string $signalType, string $platform, int $total): int
    {
        if ($signalType === 'sms') {
            if ($platform === 'B1') {
                return 0;
            }

            return $platform === 'B2'
                ? (int) ceil($total / 2)
                : (int) floor($total / 2);
        }

        $b1 = (int) ceil($total / 3);
        $b2 = (int) ceil(($total - $b1) / 2);
        $b3 = $total - $b1 - $b2;

        return match ($platform) {
            'B1' => $b1,
            'B2' => $b2,
            'B3' => $b3,
            default => 0,
        };
    }

    /**
     * @param  Collection<int, mixed>  $arrays
     * @return array<int, int>
     */
    private static function unionInts(Collection $arrays): array
    {
        return $arrays
            ->flatMap(fn ($a) => (array) $a)
            ->map(fn ($v) => (int) $v)
            ->unique()
            ->sort()
            ->values()
            ->all();
    }
}
