<?php
namespace boru\ai\Stream\Listener;

use boru\ai\Stream\StreamEvent;
use boru\ai\Stream\StreamEventListenerInterface;

class OutputBufferListener implements StreamEventListenerInterface
{
    /** @var string */
    protected $buffer = '';

    /** @var StreamEvent[] */
    protected $events = array();

    /** @var callable[] */
    protected $deltaCallbacks = array();

    /** @var callable[] */
    protected $doneCallbacks = array();

    public function onDelta($callback)
    {
        if (!is_callable($callback)) {
            throw new \InvalidArgumentException('Output buffer delta callback must be callable');
        }
        $this->deltaCallbacks[] = $callback;
        return $this;
    }

    public function onDone($callback)
    {
        if (!is_callable($callback)) {
            throw new \InvalidArgumentException('Output buffer done callback must be callable');
        }
        $this->doneCallbacks[] = $callback;
        return $this;
    }

    public function handle(StreamEvent $event)
    {
        $type = $event->type();
        if (!in_array($type, array(
            StreamEvent::TEXT_DELTA,
            StreamEvent::TEXT_COMPLETED,
        ), true)) {
            return;
        }

        $this->events[] = $event;

        if ($type === StreamEvent::TEXT_DELTA && is_string($event->delta())) {
            $this->buffer .= $event->delta();
            foreach ($this->deltaCallbacks as $callback) {
                call_user_func($callback, $event, $event->delta(), $this->buffer);
            }
        }

        if ($type === StreamEvent::TEXT_COMPLETED && is_string($event->text()) && $event->text() !== '') {
            $this->buffer = $event->text();
            foreach ($this->doneCallbacks as $callback) {
                call_user_func($callback, $event, $this->buffer);
            }
        }
    }

    public function buffer()
    {
        return $this->buffer;
    }

    public function text()
    {
        return $this->buffer();
    }

    public function events()
    {
        return $this->events;
    }
}
