<?php

namespace Ignite\Core\Models\Dashboard\Charts;

use Carbon\Carbon;
use Google_Service_AnalyticsReporting_GetReportsRequest;
use Google_Service_AnalyticsReporting_Metric;
use Ignite\Core\Services\Google\Analytics\Client;
use Ignite\Core\Models\Dashboard\Stat;

abstract class BaseGoogleAnalyticsMetric extends Stat
{
    /**
     * @var Client
     */
    private $analytics;

    /**
     * Create a new stat instance.
     *
     * @param array|object $attributes
     * @param Client $analytics
     */
    public function __construct(Client $analytics, $attributes = [])
    {
        $attributes = array_merge([
            'color' => 'white',
            'icon'  => 'ion ion-ios-person-outline',
            'link'  => '',
        ], $attributes);

        parent::__construct($attributes);

        $this->analytics = $analytics;
    }

    /**
     * The chart size in the layout.
     *
     * @return string
     */
    public function getSize()
    {
        return $this->get('size', 'col-xs-6 col-sm-3');
    }

    /**
     * Prepare the data for display.
     *
     * @param string $metric
     *
     * @return mixed
     * @throws \Google_Exception
     */
    protected function prepareData($metric)
    {
        if (! $this->get('data', false)) {
            list($start, $end) = $this->getDateRange();
            $this->attributes['data'] = $this->fetchData($metric, $start, $end);
        }

        return $this->get('data');
    }

    /**
     * The number of unique visitors for the given period
     *
     * @param string $metric
     * @param Carbon $start
     * @param Carbon $end
     *
     * @return int
     * @throws \Google_Exception
     */
    protected function fetchData($metric, Carbon $start, Carbon $end)
    {
        $period = $this->period($start, $end);
        $metric = $this->metric($metric);
        $request = $this->report($period, $metric);

        $body = new Google_Service_AnalyticsReporting_GetReportsRequest();
        $body->setReportRequests([$request]);
        $response = $this->analytics->instance()->reports->batchGet($body);

        return $this->decorate($this->value($response));
    }

    /**
     * Get the period.
     *
     * @param Carbon $start
     * @param Carbon $end
     *
     * @return \Google_Service_AnalyticsReporting_DateRange
     */
    protected function period(Carbon $start, Carbon $end)
    {
        $period = $this->analytics->period();
        $period->setStartDate($start->format('Y-m-d'));
        $period->setEndDate($end->format('Y-m-d'));

        return $period;
    }

    /**
     * Get the sessions metric.
     *
     * @param string $type
     *
     * @return Google_Service_AnalyticsReporting_Metric
     */
    protected function metric($type)
    {
        $sessions = $this->analytics->metrics();
        $sessions->setExpression("ga:$type");
        $sessions->setAlias("sessions");

        return $sessions;
    }

    /**
     * The report class.
     *
     * @param $period
     * @param Google_Service_AnalyticsReporting_Metric $sessions
     *
     * @return \Google_Service_AnalyticsReporting_ReportRequest
     */
    protected function report($period, Google_Service_AnalyticsReporting_Metric $sessions)
    {
        $request = $this->analytics->report();
        $request->setViewId(config('core.google.analytics.code'));
        $request->setDateRanges($period);
        $request->setMetrics(array($sessions));

        return $request;
    }

    /**
     * Get the metric value.
     *
     * @param \Google_Service_AnalyticsReporting_GetReportsResponse $reports
     *
     * @return int
     */
    protected function value(\Google_Service_AnalyticsReporting_GetReportsResponse $reports)
    {
        if (! isset($reports[0])) {
            return 0;
        }

        $report = $reports[0];

        /** @var \Google_Service_AnalyticsReporting_ReportRow[] $rows */
        $rows = $report->getData()->getRows();

        if (! $rows || ! isset($rows[0])) {
            return 0;
        }

        /** @var \Google_Service_AnalyticsReporting_DateRangeValues[] $metrics */
        $metrics = $rows[0]->getMetrics();

        if (! $metrics || ! isset($metrics[0])) {
            return 0;
        }

        /** @var \Google_Service_AnalyticsReporting_DateRangeValues $metric */
        $metric = $metrics[0];

        $values = $metric->getValues();

        if (! $values) {
            return 0;
        }

        return $values[0];
    }

    /**
     * Decorate the value.
     *
     * @param string $value
     *
     * @return mixed
     */
    abstract protected function decorate($value);
}
