<?php
/**
 * AJAX Chat Controller
 *
 * @package ZenoChatbot\Controller
 */

namespace ZenoChatbot\Controller;

use ZenoChatbot\App;
use ZenoChatbot\Framework\Exceptions\ValidationException;
use ZenoChatbot\Framework\Foundation\Application;
use ZenoChatbot\Framework\Support\Arr;
use ZenoChatbot\Helper\Helper;
use ZenoChatbot\Services\ChatService;
use ZenoChatbot\Services\RateLimiter;

// Prevent direct access

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

/**
 * AJAX Chat Controller for handling WordPress AJAX requests
 */
class AjaxChatController
{
    /**
     * Application instance
     *
     * @var \ZenoChatbot\Framework\Foundation\Application
     */
    private $app;

    /**
     * Chat service (session + conversation + messages)
     *
     * @var \ZenoChatbot\Services\ChatService
     */
    private $chatService;

    /**
     * Constructor
     *
     * @param \ZenoChatbot\Framework\Foundation\Application $app
     */
    public function __construct(Application $app)
    {
        $this->app = $app;
        $this->chatService = new ChatService();
    }


    /**
     * Handle chat request for both authenticated and public users
     *
     * Uses ChatService.processMessage() which handles:
     * - User message storage
     * - AI response (SavedReply or LLM)
     * - AI message storage
     * - Error handling and storage
     *
     * Frontend always receives a valid response (success or error fallback).
     */
    public function handleChatRequest()
    {
        $request = App::request();
        $message = $request->getSafe('message', 'sanitize_textarea_field');
        if (!RateLimiter::create()->allow('chat')) {
            return $this->app->response([
                'message' => 'Too many requests. Please wait a moment and try again.'
            ])->error('Too many requests.', [], 429);
        }

        try {
            $this->validateChatRequest();
        } catch (ValidationException $e) {
            return $this->app->response([
                'message' => $e->getMessage() ?? 'Please provide a message.',
                'errors'  => $e->getErrors()
            ])->error($e->getMessage());
        }

        // Get user context for new sessions
        $userContext = $this->chatService->hasExistingSession() ? [] : Helper::getSessionUserContext();

        // Optional page source (for new conversations)
        $sourceData = $this->getSourceDataFromRequest($request);

        $LLMResponse = $this->chatService->processMessage($message, $userContext, 'en', $sourceData);
        $sessionData = Helper::getSessionData();
        $payload = [
            'message'         => $LLMResponse->message,
            'session_id'      => Arr::get($sessionData, 'session_id'),
            'conversation_id' => Arr::get($sessionData, 'conversation_id'),
            'user_type'       => is_user_logged_in() ? 'authenticated' : 'public',
        ];
        if (!empty($sessionData['session_id']) && !empty($sessionData['conversation_id']) && !empty($sessionData['customer_id'])) {
            Helper::updateSession($sessionData);
        }

        // Build response payload
        return $this->app->response($payload)->success();
    }

    public function endChatSession()
    {
        try {

            $this->chatService->endSession();

            return $this->app->response([
                'message'       => 'Session ended successfully',
                'session_ended' => true,
                'user_type'     => is_user_logged_in() ? 'authenticated' : 'public'
            ])->success();

        } catch (\Exception $e) {
            // Even if error, we report the session ended to simplify client flow
            return $this->app->response([
                'message'       => 'Session ended (with errors)',
                'session_ended' => true,
                'user_type'     => is_user_logged_in() ? 'authenticated' : 'public'
            ])->success();
        }
    }

    public function getChatHistory()
    {
        if (!RateLimiter::create()->allow('history')) {
            return $this->app->response([
                'history' => [],
                'has_session' => false,
                'message' => 'Too many requests. Please wait a moment and try again.'
            ])->error('Too many requests.', [], 429);
        }

        try {

            if (!$this->chatService->hasExistingSession()) {
                return $this->app->response([
                    'history'         => [],
                    'has_session'     => false,
                    'session_id'      => null,
                    'conversation_id' => null,
                ])->success();
            }

            $history = $this->chatService->getConversationHistory();
            $sessionData = Helper::getSessionData();

            return $this->app->response([
                'history'         => Arr::get($history, 'history'),
                'conversation'    => Arr::get($history, 'conversation'),
                'has_session'     => true,
                'session_id'      => Arr::get($sessionData, 'session_id'),
                'conversation_id' => Arr::get($sessionData, 'conversation_id')
            ])->success();

        } catch (\Exception $e) {
            return $this->app->response()->success([
                'history'     => [],
                'has_session' => false,
                'error'       => 'Unable to load chat history.'
            ]);
        }
    }

    /**
     * @throws ValidationException
     */
    public function validateChatRequest()
    {
        \ZenoChatbot\Support\Conversation::validateChatRequest($this->chatService);
    }

    /**
     * Read and sanitize optional source_url, source_title, source_referrer from request.
     *
     * @param \ZenoChatbot\Framework\Http\Request $request
     * @return array{source_url?: string, source_title?: string, source_referrer?: string}
     */
    private function getSourceDataFromRequest($request): array
    {
        $sourceData = [];
        $sourceUrl = $request->getSafe('source_url', 'esc_url_raw');
        if ($sourceUrl !== '' && strlen($sourceUrl) <= 500) {
            $sourceData['source_url'] = $sourceUrl;
        }
        $sourceTitle = $request->getSafe('source_title', 'sanitize_text_field');
        if ($sourceTitle !== '' && strlen($sourceTitle) <= 255) {
            $sourceData['source_title'] = $sourceTitle;
        }
        $sourceReferrer = $request->getSafe('source_referrer', 'esc_url_raw');
        if ($sourceReferrer !== '' && strlen($sourceReferrer) <= 500) {
            $sourceData['source_referrer'] = $sourceReferrer;
        }
        return $sourceData;
    }
}
