<?php

/*
 * Copyright CADMAI Software GmbH.
 * All rights reserved.
 *
 * The redistributor / user does not have the right to change, translate,
 * back-develop, decompile or disassemble the software.
 *
 * Redistributions must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Neither the name of CADMAI Software GmbH nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

include_once ( 'funcs.php' );
require_once('Poi3d/3rdParty/parsedown/Parsedown.php');

$func = $_GET['func'];

$data = json_decode ( $_POST['data'] );

$output = [
  "mMm" => $func,
  "erC" => 0,
  "erT" => '',
  "srvInfo" => '',
  "dt" => []
];

switch ( $func ) {
  case 'AskAiBot':
    $output['erC'] = AskAiBot ( $data, $output['dt'], $output['erT'], $output['srvInfo'] );
    break;
  default:
    $output['erC'] = 1;
    $output['erT'] = 'function not implemented';
    break;
}
echo json_encode ( $output );

function AskAiBot ($data, &$ret, &$errorText, &$srvInfo)
{
  $ret = (object) [];
  $errorText = "";

  if ( iLoadUserBaseData( $data, $user, $errorText ) ) {
    return 1;
  }

  if ( empty ( $data->aiId ) ) {
    $errorText = "no ai interface defined";
    return 2;
  }

  if ( !empty ( $data->docId ) && empty ( $data->fileName ) ) {
    $errorText = "chat target not set";
    return 3;
  }

  if ( !empty ( $data->grpId ) && empty ( $data->fileName ) ) {
    $errorText = "chat target not set";
    return 3;
  }

  if ( empty ( $data->msgData ) ) {
    $errorText = "chat message template not set";
    return 4;
  }

  if ( empty ( $data->question ) ) {
    $errorText = "no question given";
    return 5;
  }

  $encTok = "";
  $salt="";

  if (! empty ( $data->slt ) ) {
    if ( iDecrypt( $data->slt, $encTok, $errorText ) ) {
      $errorText = 'decryption error: ' . $errorText;
      return 6;
    }
    else {
      $salt = $encTok->pwd;
    }
  }
  //echo "\nencTok ="; print_r($encTok);

  $msgContent = json_decode ( $data->msgData );

  // read portal configuration for chat bot
  $cfgFileName = 'portalConfig.json';
  $f = iReadFile ( $cfgFileName );

  if ( !$f ) {
    $errorText = "couldn't open " . $cfgFileName;
    return 7;
  }

  $aiBot = null;
  $fContent = json_decode ( $f );
  if(!empty ( $fContent->aiBots )) {
    foreach ( $fContent->aiBots as $ab ) {
      if($ab->aiId == $data->aiId) {
        $aiBot = $ab;
        break;
      }
    }
  }

  if ( $aiBot == null ) {
    $errorText = "no bot found";
    return 8;
  }

  if ( strlen ( $salt ) > 0 ) {
    $realKey = iDecodeText($aiBot->key,$salt);

    if (strpos($realKey, 'enc:') !== false)
      $realKey = substr($realKey,4);
  }
  else
    $realKey = $aiBot->key;

  $apiKey = $realKey;
  $provider = $aiBot->prv;

  //Test ----------------
  /*
  $date = new DateTime();
  $msgContent->cDt = $date->setTimezone(new \DateTimeZone('UTC'))->format(DateTime::ATOM);
  $msgContent->tXt = "Hello from chatbot " . $msgContent->aL;

  $data->data = json_encode ($msgContent);

  return AppendToJsonFile($data, $ret, $errorText, $srvInfo);
  */

  /*
  echo "\naibot ="; print_r($aiBot);
  $errorText = "Test";
  return 9;

  $queryData = [
      "model" => $aiBot->llm,
      "messages" => [
          ["role" => "user", "content" => $data->question]
      ],
      "max_tokens" => 200,
      "temperature" => 0.3
  ];

  */

  if ( empty ( $data->replyFrom ) ) {
    $queryData = [
        "model" => $aiBot->llm,
        "messages" => [
            ["role" => "user", "content" => $data->question]
        ],
        "stream" => false
    ];
  }
  else {
    $queryData = [
        "model" => $aiBot->llm,
        "messages" => [
            ["role" => "assistant", "content" => $data->replyFrom],
            ["role" => "user", "content" => $data->question]
        ],
        "stream" => false
    ];
  }

  if(strlen($aiBot->eP > 0)) {
    $url = $aiBot->eP;
  }
  else {
    $errorText = "no endpoint found";
    return 9;
  }

  // cURL Initialisierung
  $ch = curl_init($url);

  // Set cURL options
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Return response as string
  curl_setopt($ch, CURLOPT_POST, true); // Indicate that this is a POST request
  curl_setopt($ch, CURLOPT_TIMEOUT, 0);

  if(strlen($apiKey > 0)) {
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "Content-Type: application/json",
        "Authorization: Bearer $apiKey"
    ]);
  }
  else {
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Content-Type: application/json' // Content type as JSON
    ]);
  }

  // Convert to JSON and send the data to AI endpoint
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($queryData));

  // Execute query
  $response = curl_exec($ch);
  curl_close($ch);

  // Error handling
  if (curl_errno($ch)) {
    $errorText = curl_error($ch);
    return 10;
  }
  else {

    // decode as JSON
    $responseData = json_decode($response, true);
    /*
    echo "\nqueryData="; print_r($queryData);
    echo "\nresponseData="; print_r($responseData);
    echo "\n";
    */
    // check for answer
    if(isset($responseData['choices'][0]['message']['content'])) {
      $orgResponse = $responseData['choices'][0]['message']['content'];
    }
    else if(isset($responseData['message']['content'])) {
      $orgResponse = $responseData['message']['content'];
    }
    else {
      /*
      $errorText = "could not find answer in response";
      return 11;
      */
      $date = new DateTime();
      $msgContent->cDt = $date->setTimezone(new \DateTimeZone('UTC'))->format(DateTime::ATOM);

      $msgContent->tXt = "Query canceled (could not find answer in response)";

      if (isset($responseData['error'])){
        $msgContent->tXt = "ERROR:" . json_encode ($responseData['error']);
      }

      $data->data = json_encode ($msgContent);

      return AppendToJsonFile($data, $ret, $errorText, $srvInfo);
    }

    $date = new DateTime();
    $msgContent->cDt = $date->setTimezone(new \DateTimeZone('UTC'))->format(DateTime::ATOM);

    //plain/markup text ---------
    /*
    $msgContent->tXt = $orgResponse;
    $data->data = json_encode ($msgContent);

    AppendToJsonFile($data, $ret, $errorText, $srvInfo);
    */

    // convert markup to html
    $Parsedown = new Parsedown();
    $htmlResponse = $Parsedown->text($orgResponse);

    // delete control characters and CR
    $msgContent->tXt = preg_replace(
        ['/[\x{202F}]/u', '/[\r\n]+/', '/[\x00-\x1F\x7F]+/'],
        [' ', ' ', ''],
        $htmlResponse
    );
    /*
    echo "\norgResponse ="; print_r($orgResponse);
    echo "\nhtmlResponse ="; print_r($htmlResponse);
    echo "\nregexResponse ="; print_r($msgContent->tXt);
    */

    if ((empty( $data->docId))&&(empty( $data->grpId))) {
      $ret = $msgContent;
      return 0;
    }
    else {
      $data->data = json_encode ($msgContent);
      return AppendToJsonFile($data, $ret, $errorText, $srvInfo);
    }
  }
  return 0;
}
?>