<?php
namespace boru\boruai\Openai\Stream;

use boru\boruai\Openai\Models\BaseModel;

class StreamEvent extends BaseModel {
    private $type;
    protected $sequenceNumber;
    private $data = [];

    public function type($eventType=null) {
        if ($eventType !== null) {
            $this->type = $eventType;
        }
        return $this->type;
    }
    public function data($data=null) {
        if ($data !== null) {
            $this->data = $data;
        }
        return $this->data;
    }
    public function delta($delta=null) {
        return $delta;
    }
    public function sequenceNumber($sequenceNumber=null) {
        if ($sequenceNumber !== null) {
            $this->sequenceNumber = $sequenceNumber;
        }
        return $this->sequenceNumber;
    }

    public function get($key=null, $default=null) {
        if ($key === null) {
            return $this->data;
        }
        if(method_exists($this,$key)) {
            return $this->$key();
        }
        if(property_exists($this,$key)) {
            return $this->$key;
        }
        if(isset($this->data[$key])) {
            return $this->data[$key];
        }
        return $default;
    }

    public function toArray() {
        return $this->data;
    }
    public function __toString() {
        return json_encode($this->toArray());
    }
    public static function fromEvent($eventJsonOrArray,$callback=null) {
        if (is_string($eventJsonOrArray)) {
            $eventArray = json_decode($eventJsonOrArray, true);
        } elseif(is_array($eventJsonOrArray)) {
            $eventArray = $eventJsonOrArray;
        } else {
            throw new \Exception("Invalid event data");
        }
        if (isset($eventArray['type'])) {
            //response.output_text.delta
            //response.in_progress => Response\\InProgress
            $parts = explode('.', $eventArray['type']);
            $className = 'boru\\boruai\\Openai\\Stream\\';
            $classParts = [];
            while(count($parts) > 0) {
                $part = array_shift($parts);
                $subParts = explode('_', $part);
                $subParts = array_map('ucfirst', $subParts);
                $part = implode('', $subParts);
                $classParts[] = $part;
            }
            $className .= implode('\\', $classParts);
            if (class_exists($className)) {
                $event = new $className($eventArray);
                if ($event instanceof StreamEvent) {
                    if ($callback && is_callable($callback)) {
                        $event = call_user_func($callback, $event);
                    }
                    return $event;
                } else {
                    throw new \Exception("Class $className is not a StreamEvent");
                }
            }

            // Unknown/unmapped stream event type: fall back to a catchall event
            // instead of throwing and breaking the stream.
            $event = new UnknownEvent($eventArray);
            $event->expectedClassName($className);
            if ($callback && is_callable($callback)) {
                $event = call_user_func($callback, $event);
            }
            return $event;
        }
        return null;
    }

    const FUNCTION_CALL_COMPLETED = "function_call.completed";
    const FUNCTION_CALL_FAILED = "function_call.failed";
    const FUNCTION_CALL_FUNCTION_CALL_BASE = "function_call";
    const FUNCTION_CALL_STARTED = "function_call.started";
    const RESPONSE_OUTPUT_ITEM_DONE = "response.output_item.done";
    const RESPONSE_OUTPUT_ITEM_ADDED = "response.output_item.added";
    const RESPONSE_FUNCTION_CALL_ARGUMENTS_DELTA = "response.function_call_arguments.delta";
    const RESPONSE_FUNCTION_CALL_ARGUMENTS_DONE = "response.function_call_arguments.done";
    const RESPONSE_FILE_SEARCH_CALL_SEARCHING = "response.file_search_call.searching";
    const RESPONSE_FILE_SEARCH_CALL_COMPLETED = "response.file_search_call.completed";
    const RESPONSE_FILE_SEARCH_CALL_IN_PROGRESS = "response.file_search_call.in_progress";
    const RESPONSE_COMPLETED = "response.completed";
    const RESPONSE_WEB_SEARCH_CALL_SEARCHING = "response.web_search_call.searching";
    const RESPONSE_WEB_SEARCH_CALL_COMPLETED = "response.web_search_call.completed";
    const RESPONSE_WEB_SEARCH_CALL_IN_PROGRESS = "response.web_search_call.in_progress";
    const RESPONSE_INCOMPLETE = "response.incomplete";
    const RESPONSE_FAILED = "response.failed";
    const RESPONSE_IN_PROGRESS = "response.in_progress";
    const RESPONSE_CONTENT_PART_DONE = "response.content_part.done";
    const RESPONSE_CONTENT_PART_ADDED = "response.content_part.added";
    const RESPONSE_REFUSAL_DELTA = "response.refusal.delta";
    const RESPONSE_REFUSAL_DONE = "response.refusal.done";
    const RESPONSE_REASONING_SUMMARY_PART_DELTA = "response.reasoning_summary_part.delta";
    const RESPONSE_REASONING_SUMMARY_PART_DONE = "response.reasoning_summary_part.done";
    const RESPONSE_REASONING_SUMMARY_TEXT_DELTA = "response.reasoning_summary_text.delta";
    const RESPONSE_REASONING_SUMMARY_TEXT_DONE = "response.reasoning_summary_text.done";
    const RESPONSE_REASONING_TEXT_DELTA = "response.reasoning_text.delta";
    const RESPONSE_REASONING_TEXT_DONE = "response.reasoning_text.done";
    const RESPONSE_OUTPUT_TEXT_DELTA = "response.output_text.delta";
    const RESPONSE_OUTPUT_TEXT_DONE = "response.output_text.done";
    const RESPONSE_OUTPUT_TEXT_ADDED = "response.output_text.added";
    const RESPONSE_CREATED = "response.created";
    const RESPONSE_ERROR = "response.error";
}