<?php
// script is included in the ajax_hjandler.php and stream_handler.php and is called from Admin page and allows Admin to retrieve chatlog entries (HTML) for analysis
/*  assumes exists in parent script(s):
		TWXChatUtil access
		Wordpress context
	Customer is on Plus or Pro Plan
*/

class TWXChatLog
{


public static function getChatLogColumns(){
	return [
		'thread_id' => ['display'=>'ThreadID'],
		'chatbotId' => ['display'=>'ChatbotID','sortable'=>true,'isProperty'=>true],
		'created_dt' => ['display'=>'CreatedDT','sortable'=>true],
		'userInput' => ['display'=>'User Prompt','isProperty'=>true,'sortable'=>true],
		'isVoiceInput' => ['display'=>'Voice Input?','isProperty'=>true],
		'botResponse' => ['display'=>'Bot Response','isProperty'=>true],
		'sources' =>  ['display'=>'Sources','isProperty'=>true,'parseFunction'=>'parseSources'],
		//'botCorrections' =>  ['display'=>'Corrections','isProperty'=>true,'parseFunction'=>'parseCorrections'],
        'user_fields' => ['display'=>'User Fields','isProperty'=>true,'parseFunction'=>'parseUserFields'],
		'userHyperlinkClicks' => ['display'=>'Hyperlink Clicks','isProperty'=>true,'parseFunction'=>'parseHyperlinkClicks'],
		'feedback' => ['display'=>'User Feedback','isProperty'=>true],
	];
}

public static function getMessagesAndSourcesFromChatLog($thread_id, $system_prompt, $chatbot_greeting, $new_user_message_text, $lastN = null){

	// get user and bot messages and sources from chat thread
	// Remember! Chat Log entries are in message pairs (user msg and bot msg) so lastN will actually get back N pairs

	$msgs = [];
	$sources = [];

    if(!empty($system_prompt)){
        $msgs[] = ['role' => 'system', 'content' => $system_prompt];
    }

    /* Inserted automatically now, not needed
    if(!empty($chatbot_greeting)){
        $msgs[] = ['role' => 'assistant', 'content' => $chatbot_greeting];
    }
    */

    $entries = TWXChatLog::getChatLogEntriesByThreadId($thread_id, $lastN);
    if(!empty($entries)) {
        foreach($entries as $row){
            if(!isset($row['properties'])) continue;
            $propData = json_decode($row['properties'],true);
            if(isset($propData['userInput'])){
                $msgs[] = ['role' => 'user', 'content' => $propData['userInput']];
            }
            if(isset($propData['botResponse'])){
                $msgs[] = ['role' => 'assistant', 'content' => $propData['botResponse']];
            }
			if(isset($propData['sources'])){
				foreach($propData['sources'] as $source){
					$source_id = $source['source_id'];
					$sources[$source_id] = $source;
				}
			}
        }
    }

    if(!empty($new_user_message_text)){
        $msgs[] = ['role' => 'user', 'content' => $new_user_message_text];
    }

    return [$msgs, $sources];
}

public static function getUserFieldsFromChatLog($thread_id, $lastN = null){

	// get user and bot messages and sources from chat thread
	// Remember! Chat Log entries are in message pairs (user msg and bot msg) so lastN will actually get back N pairs

	$user_fields = [];

    $entries = TWXChatLog::getChatLogEntriesByThreadId($thread_id, $lastN);
    if(!empty($entries)) {
        foreach($entries as $row){
            if(!isset($row['properties'])) continue;
            $propData = json_decode($row['properties'],true);
			if(isset($propData['user_fields'])){
                $user_fields = array_merge($user_fields, $propData['user_fields']);
			}
        }
    }

    return $user_fields;
}

public static function getNumEntries(){

    global $wpdb;
    $table_name = $wpdb->prefix . 'twxchat_chatlog';
    return $wpdb->get_var("SELECT COUNT(*) FROM $table_name");
}

public static function getChatLogEntriesByThreadId($threadId, $lastN = null) {
    global $wpdb;

    // Define the table name with the prefix
    $table_name = $wpdb->prefix . 'twxchat_chatlog';

    // Base SQL query
    $sql = "SELECT * FROM $table_name WHERE thread_id = %s";

    // Parameters array for the prepared statement
    $params = [$threadId];

    // Modify SQL and parameters if $lastN is specified
    if ($lastN !== null) {
        // Ensure $lastN is an integer
        $lastN = (int) $lastN;

        $sql = "SELECT sub.* FROM (
                    SELECT * FROM $table_name WHERE thread_id = %s ORDER BY id DESC LIMIT %d
                ) AS sub ORDER BY id ASC";
        $params = [$threadId, $lastN];
    } else {
        $sql .= " ORDER BY id ASC";
    }

    // Prepare the SQL statement
    $prepared_query = $wpdb->prepare($sql, ...$params);

    // Execute the query and get the results
    $results = $wpdb->get_results($prepared_query, ARRAY_A);

    return $results;
}

public static function insertChatLog($threadId, $logData){
	
    global $wpdb;

    try {
        // Prepare data for insertion
        $table_name = $wpdb->prefix . 'twxchat_chatlog';
        $data = [
            'thread_id' => $threadId,
            'properties' => json_encode($logData),
        ];

        // Insert chat log into the database
        $result = $wpdb->insert($table_name, $data);

        // Check if the insertion was successful
        if ($result === false) {
            throw new Exception("Failed to insert chat log entry.");
        }


    } catch (Exception $ex) {
        // Log the error message
    }
}

public static function updateChatLogProperties($id, $properties) {

    global $wpdb;

    // Define the table name with the prefix
    $table_name = $wpdb->prefix . 'twxchat_chatlog';

    // Prepare the data for update
    $data = [
        'properties' => $properties
    ];

    // Prepare the where clause
    $where = [
        'id' => $id
    ];

    // Update the record
    $result = $wpdb->update($table_name, $data, $where);

    if ($result === false) {
        // Log the error if the update failed
        return false; // Failure
    }

    return true; // Success
}

public static function sortEntries(&$entries, $fieldIdx, $sortOrder, $cols){
	
	$colKeys = array_keys($cols);
	if($fieldIdx < 0 || $fieldIdx > count($cols)-1) return;
	$field = $colKeys[$fieldIdx];
	
	if(!isset($cols[$field]['sortable'])) return;
	if($cols[$field]['sortable'] !== true) return;
	$colData = $cols[$field];

	usort($entries, function($a, $b) use($field, $colData, $sortOrder) {
		
		if(isset($colData['isProperty'])){
			$propDataA = json_decode($a['properties'],true);
			$propDataB = json_decode($b['properties'],true);
			
			if(isset($propDataA[$field]) && isset($propDataB[$field])) {
				if($sortOrder == 'ASC') return strcmp($propDataA[$field], $propDataB[$field]);
				return strcmp($propDataB[$field], $propDataA[$field]);
			}
			return 0;
		}else{
			if($sortOrder == 'ASC') return strcmp($a[$field], $b[$field]);
			return strcmp($b[$field], $a[$field]);
		}

	});
	
}

public static function arrayToTabDelimitedCsv($array, $filename = 'chatlog.csv') {
	
    // Open a file pointer to php://output - Cant use WP Filesystem for buffering output
    $fp = fopen('php://output', 'w'); // Cant use WP Filesystem for buffering output

    // Set the headers to prompt the user to download the file
    header('Content-Type: text/tab-separated-values');
    header('Content-Disposition: attachment; filename="' . $filename . '"');

    // Output each row to the file pointer
    foreach ($array as $row) {
        // Convert each row to tab-delimited format
        fputcsv($fp, $row, ","); // Cant use WP Filesystem for buffering output
    }

    // Close the file pointer
    fclose($fp); // Cant use WP Filesystem for buffering output
    exit;
}

}