/home/bdqbpbxa/api-uniferx.goodface.com.ua/vendor/laravel/nova/src/Metrics/Value.php
<?php

namespace Laravel\Nova\Metrics;

use Carbon\CarbonImmutable;
use Illuminate\Database\Eloquent\Builder;
use Laravel\Nova\Nova;

abstract class Value extends RangedMetric
{
    use RoundingPrecision;

    /**
     * The element's component.
     *
     * @var string
     */
    public $component = 'value-metric';

    /**
     * The element's icon.
     *
     * @var string
     */
    public $icon = 'chart-bar';

    /**
     * Set the icon for the metric.
     *
     * @param  string  $icon
     * @return $this
     */
    public function icon($icon)
    {
        $this->icon = $icon;

        return $this;
    }

    /**
     * Return a value result showing the growth of an count aggregate over time.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  \Illuminate\Database\Eloquent\Builder|class-string<\Illuminate\Database\Eloquent\Model>  $model
     * @param  \Illuminate\Database\Query\Expression|string|null  $column
     * @param  string|null  $dateColumn
     * @return \Laravel\Nova\Metrics\ValueResult
     */
    public function count($request, $model, $column = null, $dateColumn = null)
    {
        return $this->aggregate($request, $model, 'count', $column, $dateColumn);
    }

    /**
     * Return a value result showing the growth of an average aggregate over time.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  \Illuminate\Database\Eloquent\Builder|class-string<\Illuminate\Database\Eloquent\Model>  $model
     * @param  \Illuminate\Database\Query\Expression|string  $column
     * @param  string|null  $dateColumn
     * @return \Laravel\Nova\Metrics\ValueResult
     */
    public function average($request, $model, $column, $dateColumn = null)
    {
        return $this->aggregate($request, $model, 'avg', $column, $dateColumn);
    }

    /**
     * Return a value result showing the growth of a sum aggregate over time.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  \Illuminate\Database\Eloquent\Builder|class-string<\Illuminate\Database\Eloquent\Model>  $model
     * @param  \Illuminate\Database\Query\Expression|string  $column
     * @param  string|null  $dateColumn
     * @return \Laravel\Nova\Metrics\ValueResult
     */
    public function sum($request, $model, $column, $dateColumn = null)
    {
        return $this->aggregate($request, $model, 'sum', $column, $dateColumn);
    }

    /**
     * Return a value result showing the growth of a maximum aggregate over time.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  \Illuminate\Database\Eloquent\Builder|class-string<\Illuminate\Database\Eloquent\Model>  $model
     * @param  \Illuminate\Database\Query\Expression|string  $column
     * @param  string|null  $dateColumn
     * @return \Laravel\Nova\Metrics\ValueResult
     */
    public function max($request, $model, $column, $dateColumn = null)
    {
        return $this->aggregate($request, $model, 'max', $column, $dateColumn);
    }

    /**
     * Return a value result showing the growth of a minimum aggregate over time.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  \Illuminate\Database\Eloquent\Builder|class-string<\Illuminate\Database\Eloquent\Model>  $model
     * @param  \Illuminate\Database\Query\Expression|string  $column
     * @param  string|null  $dateColumn
     * @return \Laravel\Nova\Metrics\ValueResult
     */
    public function min($request, $model, $column, $dateColumn = null)
    {
        return $this->aggregate($request, $model, 'min', $column, $dateColumn);
    }

    /**
     * Return a value result showing the growth of a model over a given time frame.
     *
     * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
     * @param  \Illuminate\Database\Eloquent\Builder|class-string<\Illuminate\Database\Eloquent\Model>  $model
     * @param  string  $function
     * @param  \Illuminate\Database\Query\Expression|string|null  $column
     * @param  string|null  $dateColumn
     * @return \Laravel\Nova\Metrics\ValueResult
     */
    protected function aggregate($request, $model, $function, $column = null, $dateColumn = null)
    {
        $query = $model instanceof Builder ? $model : (new $model)->newQuery();

        $query->tap(function ($query) use ($request) {
            return $this->applyFilterQuery($request, $query);
        });

        $column = $column ?? $query->getModel()->getQualifiedKeyName();

        if ($request->range === 'ALL') {
            return $this->result(
                round(
                    (clone $query)->{$function}($column),
                    $this->roundingPrecision,
                    $this->roundingMode
                )
            );
        }

        $dateColumn = $dateColumn ?? $query->getModel()->getQualifiedCreatedAtColumn();
        $timezone = Nova::resolveUserTimezone($request) ?? $this->getDefaultTimezone($request);
        $range = $request->range ?? 1;

        $currentRange = $this->currentRange($range, $timezone);
        $previousRange = $this->previousRange($range, $timezone);

        $previousValue = round(
            (clone $query)->whereBetween(
                $dateColumn, $this->formatQueryDateBetween($previousRange)
            )->{$function}($column) ?? 0,
            $this->roundingPrecision,
            $this->roundingMode
        );

        return $this->result(
            round(
                (clone $query)->whereBetween(
                    $dateColumn, $this->formatQueryDateBetween($currentRange)
                )->{$function}($column) ?? 0,
                $this->roundingPrecision,
                $this->roundingMode
            )
        )->previous($previousValue);
    }

    /**
     * Calculate the previous range and calculate any short-cuts.
     *
     * @param  string|int  $range
     * @param  string  $timezone
     * @return array<int, \Carbon\CarbonImmutable>
     */
    protected function previousRange($range, $timezone)
    {
        if ($range == 'TODAY') {
            return [
                CarbonImmutable::now($timezone)->subDay()->startOfDay(),
                CarbonImmutable::now($timezone)->subDay()->endOfDay(),
            ];
        }

        if ($range == 'YESTERDAY') {
            return [
                CarbonImmutable::now($timezone)->subDays(2)->startOfDay(),
                CarbonImmutable::now($timezone)->subDays(2)->endOfDay(),
            ];
        }

        if ($range == 'MTD') {
            return [
                CarbonImmutable::now($timezone)->subMonthWithoutOverflow()->startOfMonth(),
                CarbonImmutable::now($timezone)->subMonthWithoutOverflow(),
            ];
        }

        if ($range == 'QTD') {
            return $this->previousQuarterRange($timezone);
        }

        if ($range == 'YTD') {
            return [
                CarbonImmutable::now($timezone)->subYear()->startOfYear(),
                CarbonImmutable::now($timezone)->subYear(),
            ];
        }

        return [
            CarbonImmutable::now($timezone)->subDays($range * 2),
            CarbonImmutable::now($timezone)->subDays($range)->subSecond(),
        ];
    }

    /**
     * Calculate the previous quarter range.
     *
     * @param  string  $timezone
     * @return array<int, \Carbon\CarbonImmutable>
     */
    protected function previousQuarterRange($timezone)
    {
        return [
            CarbonImmutable::now($timezone)->subQuarterWithOverflow()->startOfQuarter(),
            CarbonImmutable::now($timezone)->subQuarterWithOverflow()->subSecond(),
        ];
    }

    /**
     * Calculate the current range and calculate any short-cuts.
     *
     * @param  string|int  $range
     * @param  string  $timezone
     * @return array<int, \Carbon\CarbonImmutable>
     */
    protected function currentRange($range, $timezone)
    {
        if ($range == 'TODAY') {
            return [
                CarbonImmutable::now($timezone)->startOfDay(),
                CarbonImmutable::now($timezone)->endOfDay(),
            ];
        }

        if ($range == 'YESTERDAY') {
            return [
                CarbonImmutable::now($timezone)->subDay()->startOfDay(),
                CarbonImmutable::now($timezone)->subDay()->endOfDay(),
            ];
        }

        if ($range == 'MTD') {
            return [
                CarbonImmutable::now($timezone)->startOfMonth(),
                CarbonImmutable::now($timezone),
            ];
        }

        if ($range == 'QTD') {
            return $this->currentQuarterRange($timezone);
        }

        if ($range == 'YTD') {
            return [
                CarbonImmutable::now($timezone)->startOfYear(),
                CarbonImmutable::now($timezone),
            ];
        }

        return [
            CarbonImmutable::now($timezone)->subDays($range),
            CarbonImmutable::now($timezone),
        ];
    }

    /**
     * Calculate the previous quarter range.
     *
     * @param  string  $timezone
     * @return array<int, \Carbon\CarbonImmutable>
     */
    protected function currentQuarterRange($timezone)
    {
        return [
            CarbonImmutable::now($timezone)->startOfQuarter(),
            CarbonImmutable::now($timezone),
        ];
    }

    /**
     * Create a new value metric result.
     *
     * @param  int|float|numeric-string|null  $value
     * @return \Laravel\Nova\Metrics\ValueResult
     */
    public function result($value)
    {
        return new ValueResult($value);
    }

    /**
     * Get default timezone.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return mixed
     */
    private function getDefaultTimezone($request)
    {
        return $request->timezone ?? config('app.timezone');
    }

    /**
     * Prepare the metric for JSON serialization.
     *
     * @return array<string, mixed>
     */
    public function jsonSerialize(): array
    {
        return array_merge(parent::jsonSerialize(), [
            'icon' => $this->icon,
        ]);
    }
}