<?php

namespace App\Classes\External;

use GuzzleHttp\Client;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

abstract class Supplier
{
	private const LOGKEY = 'AS-';

	protected $o = NULL;
	protected $_columns = [];

	public const traffic_connection_keys = ['user','pass','url'];

	public function __construct(Model $o)
	{
		$this->o = $o;
		$this->_columns = collect();
	}

	/**
	 * Connect and pull down traffic data
	 *
	 * @param array $connection
	 * @param string $type
	 * @return Collection
	 * @throws \Exception
	 */
	public function fetch(array $connection,string $type): Collection
	{
		if (count(array_intersect(array_keys($connection),self::traffic_connection_keys)) !== 3)
			throw new \Exception('No or missing connection details for:'.$type);

		if ($x=$this->mustPause()) {
			Log::notice(sprintf('%s:API Throttle, waiting [%s]...',self::LOGKEY,$x),['m'=>__METHOD__]);
			sleep($x);
		}

		Log::debug(sprintf('%s:Supplier [%d], fetch data for [%s]...',self::LOGKEY,$this->o->id,Arr::get($connection,'last')),['m'=>__METHOD__]);
		$key = 'Supplier:'.$this->o->id.Arr::get($connection,'last');

		$result = Cache::remember($key,86400,function() use ($connection) {
			$response = Http::get(Arr::get($connection,'url'),[
				$this->login_user_field => Arr::get($connection,'user'),
				$this->login_pass_field => Arr::get($connection,'pass'),
				$this->date_field => Arr::get($connection,'last'),
			]);

			// @todo These API rate limiting is untested.
			$api_remain = $response->header('X-RateLimit-Remaining');
			$api_reset = $response->header('X-RateLimit-Reset');

			if ($api_remain === 0 AND $api_reset) {
				Log::notice(sprintf('%s:API Throttle [%d].',self::LOGKEY,$api_reset),['m'=>__METHOD__]);
				Cache::put('api_throttle',$api_reset,now()->addSeconds($api_reset));
			}

			// Assume the supplier provides an ASCII output for text/html
			if (preg_match('#^text/html;#',$x=$response->header('Content-Type'))) {
				return collect(explode("\n",$response->body()))->filter();

			} else {
				Log::error(sprintf('%s:Havent handled header type [%s]',self::LOGKEY,$x),['m'=>__METHOD__]);
				throw new \Exception('Unhandled Content Type');
			}
		});

		Log::debug(sprintf('%s:Supplier [%d], records returned [%d]...',self::LOGKEY,$this->o->id,$result->count()),['m'=>__METHOD__]);

		return $result;
	}

	/**
	 * Return the API HTTP client
	 * @return Client
	 */
	protected function getClient(): Client
	{
		return new Client(['base_uri'=>$this->o->stats_url]);
	}

	/**
	 * Return the expected columns from a supplier traffic import
	 *
	 * @param string     $line
	 * @param Collection $expect
	 * @return Collection
	 */
	public function getColumns(string $line,Collection $expect): Collection
	{
		$fields = collect(explode(',',$line))->filter();
		$this->_columns = $expect;
		if ($this->_columns->diff($fields)->count()) {
			abort('500','Missing columns in data: '.join('|',$this->_columns->diff($fields)->toArray()).' got: '.join('|',$fields));
		}

		return $fields->intersect($this->_columns);
	}

	/**
	 * Return the key ID for a column
	 *
	 * @param string $key
	 * @return mixed
	 */
	public function getColumnKey(string $key)
	{
		return $this->_columns->search($key);
	}

	public function header(): array
	{
		return static::$header;
	}

	/**
	 * If the supplier has API throttling...
	 *
	 * @return mixed
	 */
	protected function mustPause()
	{
		return Cache::get('api_throttle');
	}
}