<?php

namespace Tobuli\History\Actions;

class AppendFuelConsumptions extends ActionAppend
{
    protected $sensors = [];

    protected $consumptions = [];

    protected $diffs = [];

    protected $fuel_per_km;

    protected $min_fuel_fillings;

    protected $fuel_tanks = [];

    static public function required()
    {
        return [
            AppendDistance::class,
            AppendMoveState::class
        ];
    }

    public function boot()
    {
        $this->min_fuel_fillings = $this->history->config('min_fuel_fillings');

        $this->loadConsumptionGPS();
        $this->loadConsumptionSensors();
    }

    public function proccess(& $position)
    {
        foreach ($this->sensors as $sensor)
            $this->proccessSensor($sensor, $position);

        if ($this->fuel_per_km)
            $this->consumptions['gps'] = $position->distance * $this->fuel_per_km;

        $position->consumptions = $this->consumptions;
        $position->fuel_tanks = $this->fuel_tanks;
    }

    protected function proccessSensor($sensor, & $position)
    {
        $value = $this->getSensorValue($sensor, $position);

        $this->fuel_tanks[$sensor->id] = $value;

        $prevPosition = $this->getPrevPosition();

        if ( ! $prevPosition)
            return;

        $prevValue = $this->getSensorValue($sensor, $prevPosition);

        if (empty($value) || empty($prevValue))
            return;

        $diff = $value - $prevValue;

        $this->consumptions[$sensor->id] = (-1) * $diff;

        $diffs = & $this->diffs[$sensor->id];

        $count_diffs = count($diffs);

        if ($count_diffs > 2)
        {
            $diff_sum = array_sum($diffs);

            $diffs = array_filter($diffs, function($v) use ($diff_sum, $count_diffs)
            {
                if (empty($v))
                    return false;

                return abs($diff_sum / $v) >= 0.1;
            });

            $count_diffs = count($diffs);
        }

        $filling = 0;
        $increasing = $diff > 0;

        //condition
        if ( ! $increasing && $count_diffs > 4 ) {
            $filling = $this->getFillingFromDiffs($diffs);
            $diffs = array_slice($diffs, -20, 20);
        }

        $diffs[] = $diff;

        # Filling
        if (!is_null($this->min_fuel_fillings) &&
            $filling > $this->min_fuel_fillings &&
            ($position->moving == AppendMoveState::STOPED || $prevPosition->moving == AppendMoveState::STOPED)
        )
        {
            $this->consumptions[$sensor->id] += $filling;

            $position->fuel_filling = [
                'sensor_id' => $sensor->id,
                'previous'  => $value + $diff - $filling,
                'current'   => $value + $diff,
                'diff'      => $filling,
                'unit'      => $sensor->unit_of_measurement
            ];

            # clean diffs
            $diffs = array_slice($diffs, -1, 1);

            $this->fire('fuel.filling');
        }
    }

    protected function getFillingFromDiffs($diffs)
    {
        $filling = 0;
        $increasing = false;

        foreach ($diffs as $diff) {
            if ( ! $increasing && $diff < 0)
                continue;

            $increasing = true;

            $filling += $diff;
        }

        return $filling;
    }

    protected function loadConsumptionGPS()
    {
        $device = $this->getDevice();

        if ( $device->fuel_per_km > 0)
        {
            $this->fuel_per_km = (float) $device->fuel_per_km;

            $this->consumptions['gps'] = 0;
        }
    }

    protected function loadConsumptionSensors()
    {
        $device = $this->getDevice();

        foreach ($device->sensors as $sensor)
        {
            if ( ! in_array($sensor->type, ['fuel_tank', 'fuel_tank_calibration']))
                continue;

            if ($sensor->fuel_tank > 100 && $this->min_fuel_fillings == 10)
                $this->min_fuel_fillings = $sensor->fuel_tank * 0.3;

            $this->sensors[] = $sensor;

            $this->consumptions[$sensor->id] = 0;
            $this->diffs[$sensor->id] = [];

            $this->fuel_tanks[$sensor->id] = null;
        }
    }
}