<?php

namespace Ignite\Core\Models\Dashboard\Charts;

use Carbon\Carbon;
use Ignite\Core\Contracts\Dashboard\WithInlineSeries;
use Ignite\Core\Contracts\Dashboard\WithPercentageChange;
use Ignite\Core\Entities\User;
use Ignite\Core\Facades\Format;
use Ignite\Core\Models\Dashboard\Concerns\DeterminesPercentageChange;
use Ignite\Core\Models\Dashboard\Stat;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;

class TransactionsEarnedStat extends Stat implements WithPercentageChange, WithInlineSeries
{
    use DeterminesPercentageChange;

    /**
     * Create a new stat instance.
     *
     * @param  array|object $attributes
     */
    public function __construct($attributes = [])
    {
        $attributes = array_merge([
            'label' => 'Amount earned',
            "type" =>  "metric",
            'sort'  => 2
        ], $attributes);

        parent::__construct($attributes);
    }

    /**
     * The HTML element ID.
     *
     * @return string
     */
    public function getElement()
    {
        return 'transaction-amount-earned-stat';
    }

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

    /**
     * Get the correct data value from storage.
     *
     * @return mixed
     */
    public function getData()
    {
        if (! $this->get('data', false)) {
            $result = DB::table('core_transaction')
                ->select(DB::raw('COUNT(id) as total'))
                ->selectSub($this->getSubQuery($this->getDateRange()), 'current')
                ->selectSub($this->getSubQuery($this->getPreviousDateRange()), 'previous')
                ->first();

            $this->setPercentageChange($result->current, $result->previous);

            $this->offsetSet('data', Format::balance($result->current));
        }

        if ($this instanceof WithInlineSeries) {
            $this->setSeries($this->getSeriesData());
        }

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

    /**
     * Get the sub-query with date contraints.
     *
     * @param array $range
     *
     * @return Builder
     */
    protected function getSubQuery(array $range)
    {
        return $sub = DB::table('core_transaction')
            ->selectRaw('SUM(ABS(value))')
            ->whereNull('deleted_at')
            ->whereIn('type', ['MANUAL-RECEIVE', 'EARNED'])
            ->whereRaw(
                'DATE(created_at) BETWEEN ? AND ?',
                $range
            );
    }

    /**
     * Query the database for series data.
     *
     * @return array
     */
    protected function getSeriesData()
    {
        $results = $this->scope($this->buildRangedQuery($this->getDateRange()))->get();

        return $results->keyBy('date')->map->total->toArray();
    }

    /**
     * Scope the query.
     *
     * @param Builder $query
     *
     * @return Builder
     */
    protected function scope(Builder $query)
    {
        $query->whereIn('type', ['MANUAL-RECEIVE', 'EARNED']);

        return $query;
    }

    /**
     * The query scoped to the given range.
     *
     * @param array $range
     *
     * @return Builder
     */
    protected function buildRangedQuery($range)
    {
        return DB::table('core_transaction')
                 ->selectRaw('DATE(created_at) as `date`, SUM(ABS(value)) as `total`')
                 ->whereNull('deleted_at')
                 ->groupBy('date')
                 ->havingBetween('date', $range)
                 ->orderBy('date', 'asc');
    }

    /**
     * Set the percentage change values using current versus previous ranges.
     *
     * @param int|float $current
     * @param int|float $previous
     *
     * @return self
     */
    public function setPercentageChange($current, $previous)
    {
        $this->offsetSet('current', number_format($current, 0));
        $this->offsetSet('previous', number_format($previous, 0));
        $this->offsetSet('direction', $this->determineChangeType($current, $previous));
        $this->offsetSet('percentage', $this->determinePercentageChange($current, $previous));

        return $this;
    }

    public function setSeries(array $data)
    {
        $values = [];
        $type = 'month';

        foreach ($data as $date => $value) {
            if ($type === 'month') {
                $key = Carbon::parse($date)->format('d');
            } else {
                $key = $date;
            }
            $values[$key] = round($value, PHP_ROUND_HALF_DOWN);
        }

        $this->offsetSet('series', $values);
    }
}
