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

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

class CompletionStatusListener implements StreamEventListenerInterface
{
    /** @var string|null */
    protected $status;

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

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

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

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

    public function onCompleted($callback)
    {
        if (!is_callable($callback)) {
            throw new \InvalidArgumentException('Completion listener callback must be callable');
        }
        $this->completedCallbacks[] = $callback;
        return $this;
    }

    public function onFailed($callback)
    {
        if (!is_callable($callback)) {
            throw new \InvalidArgumentException('Failed listener callback must be callable');
        }
        $this->failedCallbacks[] = $callback;
        return $this;
    }

    public function onError($callback)
    {
        if (!is_callable($callback)) {
            throw new \InvalidArgumentException('Error listener callback must be callable');
        }
        $this->errorCallbacks[] = $callback;
        return $this;
    }

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

        $this->events[] = $event;

        if ($type === StreamEvent::TURN_COMPLETED) {
            $this->status = 'completed';
            foreach ($this->completedCallbacks as $callback) {
                call_user_func($callback, $event, $this->status);
            }
        } elseif ($type === StreamEvent::TURN_FAILED) {
            $this->status = 'failed';
            foreach ($this->failedCallbacks as $callback) {
                call_user_func($callback, $event, $this->status);
            }
        } elseif ($type === StreamEvent::TURN_ERROR) {
            $this->status = 'error';
            foreach ($this->errorCallbacks as $callback) {
                call_user_func($callback, $event, $this->status);
            }
        }
    }

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

    public function completed()
    {
        return $this->status === 'completed';
    }

    public function failed()
    {
        return $this->status === 'failed';
    }

    public function errored()
    {
        return $this->status === 'error';
    }

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