HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/ai.naniguide.com/app/Services/Customer/SendingServerService.php
<?php

namespace App\Services\Customer;

use App\Dto\Refactor\SendingServer\SendingServerSidebarStatsDto;
use App\Model\Customer;
use App\Model\SendingServer;
use App\SendingServers\DriverRegistry;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;

/**
 * Read aggregator for the customer-side rich-redesigned "Sending Servers" page.
 * Owned scope: stats meta, filtered list, sidebar widgets (vendor mix donut,
 * combined throughput, warmup status, service catalog).
 */
class SendingServerService
{
    /**
     * @return array{total:int,active:int,inactive:int,warmup:int,vendors:int}
     */
    public function headerMeta(Customer $customer): array
    {
        $base = SendingServer::query()->where('customer_id', $customer->id);

        $total = (clone $base)->count();
        $active = (clone $base)->where('status', SendingServer::STATUS_ACTIVE)->count();
        $inactive = max(0, $total - $active);
        $warmup = (clone $base)->where('warmup_enabled', 1)->count();
        $vendors = (clone $base)->distinct('type')->count('type');

        return [
            'total' => $total,
            'active' => $active,
            'inactive' => $inactive,
            'warmup' => $warmup,
            'vendors' => $vendors,
        ];
    }

    public function list(
        Customer $customer,
        ?string $keyword = null,
        ?string $status = null,
        ?string $type = null,
        string $sortBy = 'created_at',
        string $sortDir = 'desc',
        int $perPage = 25,
    ): LengthAwarePaginator {
        $query = SendingServer::query()->where('customer_id', $customer->id);

        if ($keyword !== null && $keyword !== '') {
            $query->where('name', 'like', '%' . $keyword . '%');
        }

        if ($status === 'active') {
            $query->where('status', SendingServer::STATUS_ACTIVE);
        } elseif ($status === 'inactive') {
            $query->where(function ($q) {
                $q->where('status', '!=', SendingServer::STATUS_ACTIVE)
                    ->orWhereNull('status');
            });
        }

        if ($type !== null && $type !== '') {
            $query->where('type', $type);
        }

        $allowedSorts = ['created_at', 'name', 'type', 'status'];
        if (! in_array($sortBy, $allowedSorts, true)) {
            $sortBy = 'created_at';
        }
        $sortDir = strtolower($sortDir) === 'asc' ? 'asc' : 'desc';

        return $query->orderBy($sortBy, $sortDir)->paginate($perPage);
    }

    public function sidebarStats(Customer $customer): SendingServerSidebarStatsDto
    {
        return new SendingServerSidebarStatsDto(
            headerMeta: $this->headerMeta($customer),
            vendorMix: $this->vendorMix($customer),
            throughput: $this->throughput($customer),
            warmupStatus: $this->warmupStatus($customer),
            coverage: $this->coverage($customer),
        );
    }

    /** @return array{slices:list<array{key:string,name:string,count:int}>,total:int} */
    private function vendorMix(Customer $customer): array
    {
        $rows = \Illuminate\Support\Facades\DB::table('sending_servers')
            ->where('customer_id', $customer->id)
            ->selectRaw('type, COUNT(*) as cnt')
            ->groupBy('type')
            ->get();

        $slices = [];
        $total = 0;
        foreach ($rows as $row) {
            $type = (string) $row->type;
            $cnt = (int) $row->cnt;
            $slices[] = [
                'key' => $type,
                'name' => $this->vendorLabel($type),
                'count' => $cnt,
            ];
            $total += $cnt;
        }

        usort($slices, fn ($a, $b) => $b['count'] <=> $a['count']);

        return ['slices' => $slices, 'total' => $total];
    }

    /** @return array{total_per_hour:int,formatted:string,by_vendor:list<array{key:string,name:string,per_hour:int}>} */
    private function throughput(Customer $customer): array
    {
        $servers = SendingServer::query()
            ->where('customer_id', $customer->id)
            ->where('status', SendingServer::STATUS_ACTIVE)
            ->get(['type', 'quota_value', 'quota_base', 'quota_unit']);

        $byVendor = [];
        $total = 0;

        foreach ($servers as $server) {
            $value = (int) ($server->quota_value ?? 0);
            $base = max(1, (int) ($server->quota_base ?? 1));
            $unit = (string) ($server->quota_unit ?? 'hour');

            if ($value <= 0) {
                continue;
            }

            $perBase = $value / $base;
            $perHour = match ($unit) {
                'minute' => (int) round($perBase * 60),
                'hour' => (int) round($perBase),
                'day' => (int) round($perBase / 24),
                default => 0,
            };

            if ($perHour <= 0) {
                continue;
            }

            $key = (string) $server->type;
            if (! isset($byVendor[$key])) {
                $byVendor[$key] = ['key' => $key, 'name' => $this->vendorLabel($key), 'per_hour' => 0];
            }
            $byVendor[$key]['per_hour'] += $perHour;
            $total += $perHour;
        }

        $byVendor = array_values($byVendor);
        usort($byVendor, fn ($a, $b) => $b['per_hour'] <=> $a['per_hour']);

        return [
            'total_per_hour' => $total,
            'formatted' => $total > 0 ? number_format($total) . '/hour' : '—',
            'by_vendor' => $byVendor,
        ];
    }

    /** @return array{enabled:int,disabled:int,started:int} */
    private function warmupStatus(Customer $customer): array
    {
        $base = SendingServer::query()->where('customer_id', $customer->id);
        $enabled = (clone $base)->where('warmup_enabled', 1)->count();
        $started = (clone $base)->where('warmup_enabled', 1)->whereNotNull('warmup_started_at')->count();
        $disabled = max(0, (clone $base)->count() - $enabled);

        return [
            'enabled' => $enabled,
            'disabled' => $disabled,
            'started' => $started,
        ];
    }

    /** @return array{used_vendor_keys:list<string>,catalog:list<array{key:string,name:string,connected:bool,count:int}>} */
    private function coverage(Customer $customer): array
    {
        $rows = \Illuminate\Support\Facades\DB::table('sending_servers')
            ->where('customer_id', $customer->id)
            ->selectRaw('type, COUNT(*) as cnt')
            ->groupBy('type')
            ->pluck('cnt', 'type')
            ->all();

        $catalog = [];
        $usedKeys = [];

        try {
            $allTypes = array_keys(DriverRegistry::all() ?: []);
        } catch (\Throwable $e) {
            $allTypes = array_keys($rows);
        }
        // Merge in any used types that are not in the registry (defensive).
        foreach (array_keys($rows) as $t) {
            if (! in_array($t, $allTypes, true)) {
                $allTypes[] = $t;
            }
        }

        foreach ($allTypes as $type) {
            $catalog[] = [
                'key' => $type,
                'name' => $this->vendorLabel($type),
                'connected' => isset($rows[$type]),
                'count' => (int) ($rows[$type] ?? 0),
            ];
            if (isset($rows[$type])) {
                $usedKeys[] = $type;
            }
        }

        usort($catalog, function ($a, $b) {
            if ($a['connected'] !== $b['connected']) {
                return $a['connected'] ? -1 : 1;
            }
            return strcasecmp($a['name'], $b['name']);
        });

        return [
            'used_vendor_keys' => $usedKeys,
            'catalog' => $catalog,
        ];
    }

    private function vendorLabel(string $type): string
    {
        $key = 'refactor/sending.servers.type.' . $type;
        $label = trans($key);
        if ($label === $key) {
            return \Illuminate\Support\Str::title(str_replace(['-', '_'], ' ', $type ?: '—'));
        }
        return (string) $label;
    }
}