<?php
namespace nur\mapper\base;

use nur\mapper\base\impl\Add2Mapper;
use nur\mapper\base\impl\AddMapper;
use nur\mapper\base\impl\NumberProducer;
use nur\mapper\base\impl\PlusOneMapper;
use nur\mapper\base\impl\ResultConsumer;
use nur\mapper\base\impl\TwiceMapper;
use nur\t\TestCase;

class ConsumerTest extends TestCase {
  function testConsumer1() {
    $numberProducer = new class() extends Producer {
      function producer() {
        yield from [1, 2, 3, 4];
      }
    };
    $plusOne = new class(null) extends Mapper {
      function mapper($item) {
        return $item + 1;
      }
    };
    $twice = new class(null) extends Mapper {
      function mapper($item) {
        return $item * 2;
      }
    };

    $consumer = new class($numberProducer, $plusOne, $twice) extends Consumer {
      public $result = [];
      function cook($item) {
        $this->result[] = $item;
      }
    };
    $consumer->consume();
    self::assertSame([4, 6, 8, 10], $consumer->result);
  }

  function testConsumer2() {
    $consumer = new ResultConsumer(NumberProducer::class);
    $consumer->add(PlusOneMapper::class);
    $consumer->add(TwiceMapper::class);
    $consumer->consume();
    self::assertSame([4, 6, 8, 10], $consumer->result);
  }

  function testConsumer3() {
    $consumer = new ResultConsumer([1, 2, 3, 4], PlusOneMapper::class, TwiceMapper::class);
    $consumer->consume();
    self::assertSame([4, 6, 8, 10], $consumer->result);
  }

  function testConsumer4() {
    $consumer = new class extends Consumer {
      private $count;
      function getCount(): int {
        return $this->count;
      }

      private $sum;
      function getSum(): int {
        return $this->sum;
      }

      function cook($item) {
        $this->count++;
        $this->sum += $item;
      }
    };
    $consumer->consume([1, 2, 3, 4], function ($value) {
      return $value + 1;
    });
    self::assertSame(4, $consumer->getCount());
    self::assertSame(14, $consumer->getSum());
  }

  function testConsumer5() {
    $consumer = new ResultConsumer([1, 2, 3, 4], [AddMapper::class, 1]);
    $consumer->consume();
    self::assertSame([2, 3, 4, 5], $consumer->result);
  }

  function testConsumer6() {
    $consumer = new ResultConsumer(null, [AddMapper::class, 1]);
    $consumer->push(1);
    self::assertSame([2], $consumer->result);
    $consumer->pushAll([2, 3]);
    self::assertSame([2, 3, 4], $consumer->result);
    $consumer->push(4);
    self::assertSame([2, 3, 4, 5], $consumer->result);
    $consumer->close();
  }

  function testPushMix() {
    $consumer = new ResultConsumer(NumberProducer::class, [AddMapper::class, 1]);
    $consumer->push(10);
    self::assertSame([11], $consumer->result);
    $consumer->consume();
    self::assertSame([11], $consumer->result);
    $consumer->close();
    $consumer->consume();
    self::assertSame([11, 2, 3, 4, 5], $consumer->result);

    $consumer = new ResultConsumer(NumberProducer::class, [AddMapper::class, 1]);
    $consumer->consume();
    self::assertSame([2, 3, 4, 5], $consumer->result);
    $consumer->push(10);
    self::assertSame([2, 3, 4, 5, 11], $consumer->result);
    $consumer->close();

    $consumer = new ResultConsumer(NumberProducer::class, [AddMapper::class, 1]);
    $consumer->consume();
    self::assertSame([2, 3, 4, 5], $consumer->result);
    $consumer->consume();
    self::assertSame([2, 3, 4, 5, 2, 3, 4, 5], $consumer->result);
    $consumer->push(10);
    self::assertSame([2, 3, 4, 5, 2, 3, 4, 5, 11], $consumer->result);
    $consumer->consume();
    self::assertSame([2, 3, 4, 5, 2, 3, 4, 5, 11], $consumer->result);
    $consumer->close();
    $consumer->consume();
    self::assertSame([2, 3, 4, 5, 2, 3, 4, 5, 11, 2, 3, 4, 5], $consumer->result);
  }

  function testDefaultArgs() {
    $consumer = new ResultConsumer(NumberProducer::class
      , [Add2Mapper::class, 1] # 1
      , [Add2Mapper::class, 1, 2] # 3
      , [Add2Mapper::class, 1, 2, 3] # 6
    );
    $consumer->consume();
    self::assertSame([11, 12, 13, 14], $consumer->result);
  }
}
