<?php

namespace Ignite\Core\Models\Dashboard;

use Illuminate\Support\Carbon;
use Illuminate\Support\Fluent;
use Ignite\Core\Contracts\Dashboard\Chart as ChartInterface;

abstract class Chart extends Fluent implements ChartInterface
{
    /**
     * @var string[]
     */
    protected $colors = [
        'primary' => '#3c8dbc',
        'aqua' => '#00c0ef',
        'navy' => '#001F3F',
        'teal' => '#39CCCC',
        'red' => '#f56954',
        'orange' => '#ff851b',
        'yellow' => '#f39c12',
        'green' => '#00a65a',
        'gray' => '#d2d6de',
        'maroon' => '#D81B60',
        'purple' => '#605ca8',
    ];

    /**
     * Create a new stat instance.
     *
     * @param  array|object $attributes
     */
    public function __construct($attributes = [])
    {
        parent::__construct(array_merge([
            'element' => $this->getElement(),
            'size' => 'col-xs-12 col-sm-6 col-md-4 col-lg-3'
        ], $attributes ?? []));
    }

    /**
     * Convert the given color name to hex.
     *
     * @param string $color
     * @param string $default
     *
     * @return string
     */
    protected function colorToHex(string $color, string $default = '#3c8dbc')
    {
        if (! array_key_exists($color, $this->colors)) {
            return $default;
        }

        return $this->colors[$color];
    }

    /**
     * Computed hex value from color attribute.
     *
     * @return string
     */
    public function getHex()
    {
        $hex = $this->colorToHex($this->get('color'));
        $this->offsetSet('hex', $hex);

        return $hex;
    }

    /**
     * The label to describe the stat.
     *
     * @return string
     */
    public function getLabel()
    {
        return $this->get('label');
    }

    /**
     * The date range from the request.
     *
     * @return array
     */
    public function getDateRange()
    {
        $defaultStart = today()->subDays(config('core.dashboard.startCurrentOffsetDays', 7));
        $defaultEnd = today()->subDays(config('core.dashboard.endCurrentOffsetDays', 0));

        $start = Carbon::parse(request()->query('current-start', $defaultStart));
        $end = Carbon::parse(request()->query('current-end', $defaultEnd));

        return [$start->startOfDay(), $end->endOfDay()];
    }

    /**
     * The date range from the request.
     *
     * @return array
     */
    public function getPreviousDateRange()
    {
        $defaultStart = today()->subDays(config('core.dashboard.startPreviousOffsetDays', 14));
        $defaultEnd = today()->subDays(config('core.dashboard.endPreviousOffsetDays', 7));

        $start = Carbon::parse(request()->query('previous-start', $defaultStart));
        $end = Carbon::parse(request()->query('previous-end', $defaultEnd));

        return [$start->startOfDay(), $end->endOfDay()];
    }

    /**
     * Process the chart.
     *
     * @return $this
     */
    public function process()
    {
        $this->getData();

        return $this;
    }

    /**
     * Use the cached attributes to generate the chart data.
     *
     * @return $this
     */
    protected function cache()
    {
        $cache = app('cache');
        $key = $this->cacheKey();

        if ($cache->has($key)) {
            $this->attributes = $cache->get($key);
            return $this;
        }

        $cache->put($key, $this->attributes, 10);
        $this->getData();

        return $this;
    }

    /**
     * Generate the cache key.
     *
     * @return string
     */
    protected function cacheKey()
    {
        $date = md5(vsprintf('%s-%s', $this->getDateRange()));

        return "charts.{$this->getType()}.{$this->getElement()}.{$date}";
    }

    /**
     * Convert the fluent instance to an array.
     *
     * @return array
     */
    public function toArray()
    {
        $attributes = [];

        foreach ($this->attributes as $key => $value) {
            if ($key === 'colors') {
                $value = $this->mapColorNamesToHex($value);
            }

            $attributes[$key] = $value;
        }

        return $attributes;
    }

    protected function mapColorNamesToHex($colors)
    {
        return array_map(function ($color) {
            return $this->colorToHex($color, $color);
        }, $colors);
    }
}
