<?php

namespace ZenoChatbot\Services;

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Unified response object for chat responses
 * Used by ChatService to return consistent response format
 *
 * Handles both successful responses and errors uniformly.
 * Frontend always receives a valid message - it doesn't know about errors.
 */
class ChatResponse
{
    /**
     * The response message (always valid, even for errors - contains fallback)
     */
    public string $message;

    /**
     * Source of the response: 'saved_reply' | 'llm' | 'error'
     */
    public string $source;

    /**
     * Whether the response was successful
     */
    public bool $success;

    /**
     * Error message (null if success)
     */
    public ?string $error;

    /**
     * Error code for categorization (null if success)
     * Codes: SAFETY_FILTER, RATE_LIMIT, AUTH_ERROR, EMPTY_RESPONSE, TIMEOUT, CONFIG_ERROR, UNKNOWN
     */
    public ?string $errorCode;

    /**
     * Additional metadata about the response
     */
    public array $metadata;

    /**
     * Create a new ChatResponse instance
     *
     * @param string $message The response message
     * @param string $source Source identifier ('saved_reply', 'llm', 'error')
     * @param array $metadata Additional metadata
     * @param bool $success Whether the response was successful
     * @param string|null $error Error message (null if success)
     * @param string|null $errorCode Error code for categorization
     */
    public function __construct(
        string $message,
        string $source = 'llm',
        array $metadata = [],
        bool $success = true,
        ?string $error = null,
        ?string $errorCode = null
    ) {
        $this->message = $message;
        $this->source = $source;
        $this->metadata = $metadata;
        $this->success = $success;
        $this->error = $error;
        $this->errorCode = $errorCode;
    }

    /**
     * Create an error response with fallback message
     *
     * @param string $fallbackMessage Message to show to user
     * @param string $error Actual error message (stored in DB, not shown to user)
     * @param string $errorCode Error code for categorization
     * @param array $metadata Additional metadata
     * @return self
     */
    public static function error(
        string $fallbackMessage,
        string $error,
        string $errorCode = 'UNKNOWN',
        array $metadata = []
    ): self {
        return new self(
            $fallbackMessage,
            'error',
            $metadata,
            false,
            $error,
            $errorCode
        );
    }

    /**
     * Check if response is from a saved reply
     */
    public function isSavedReply(): bool
    {
        return $this->source === 'saved_reply';
    }

    /**
     * Check if response is from LLM
     */
    public function isLLM(): bool
    {
        return $this->source === 'llm';
    }

    /**
     * Check if response is an error
     */
    public function isError(): bool
    {
        return $this->source === 'error' || !$this->success;
    }

    /**
     * Check if response was successful
     */
    public function isSuccess(): bool
    {
        return $this->success;
    }

    /**
     * Get a metadata value
     *
     * @param string $key Metadata key
     * @param mixed $default Default value if key not found
     * @return mixed
     */
    public function getMeta(string $key, $default = null)
    {
        return $this->metadata[$key] ?? $default;
    }

    /**
     * Convert to array (for JSON serialization)
     * Note: Does NOT include error details - those are internal only
     */
    public function toArray(): array
    {
        return [
            'message' => $this->message,
            'source' => $this->source,
            'success' => $this->success,
            'metadata' => $this->metadata,
        ];
    }
}

