<?php
namespace boru\boruai\Models;

use boru\boruai\BoruAI;
use boru\boruai\Openai\OpenAIEmbedding;
use boru\dhprocess\Task;
use boru\dhprocess\TaskQueue;
use boru\query\Query;
use boru\query\Entity;
use boru\query\Factory;
use boru\query\models\EntityDefinition;
use boru\query\models\Value;

class Embedding extends Entity {
    private $entity;
    public static function entityDefinition() {
        $tableName = BoruAI::table('embeddings');
        $query = Query::create()->select('*')->from($tableName);
        return new EntityDefinition([
            "className" => static::class,
            "name" => "Embedding",
            "queryBase" => $query,
            "jsonFields" => ['vector'],
            'createdField' => 'created',
        ]);
    }
    public function __construct($idOrData=null) {
        parent::__construct($idOrData);
    }

    public static function cacheExpire($expire=null) {
        if($expire !== null) {
            BoruAI::setConfig("embeddings.cache.expire", $expire);
        }
        return BoruAI::config("embeddings.cache.expire", 60*60*24*7);
    }
    public static function maxLength($maxLength=null) {
        if($maxLength !== null) {
            BoruAI::setConfig("embeddings.cache.max_length", $maxLength);
        }
        return BoruAI::config("embeddings.cache.max_length", 250);
    }

    public static function cleanCache() {
        $expire = static::cacheExpire();
        $tableName = BoruAI::table('embeddings');
        $query = Query::create()->delete()->from($tableName)->where('created','<',Value::functionValue('DATE_SUB(NOW(), INTERVAL '.$expire.' SECOND)'));
        $query->run();
    }

    public function id($id=null) {
        if($id !== null) {
            return $this->set('id',$id);
        }
        return $this->get('id');
    }

    public function md5($md5=null) {
        if($md5) {
            return $this->set('md5',$md5);
        }
        return $this->get('md5');
    }

    public function query($query=null) {
        if($query) {
            $md5 = md5($query);
            $this->set('md5',$md5);
            return $this->set('query',$query);
        }
        return $this->get('query');
    }

    public function vector($vector=null) {
        if($vector) {
            return $this->set('vector',$vector);
        }
        return $this->get('vector');
    }

    public function save() {
        return parent::save();
    }

    public static function find($query) {
        $md5 = md5($query);
        $tableName = BoruAI::table('embeddings');
        $query = Query::create()->select('*')->from($tableName)->where('md5','=',$md5);
        foreach($query->toRows() as $row) {
            return new static($row->asArray());
        }
        return false;
    }

    /**
     * Embed a string
     * @param string $string The string to embed
     * @param boolean $useCache If true, use the cache
     * @param boolean $vectorOnly If true, only return the vector
     * @return array|Embedding Returns the Embedding object or the vector
     */
    public static function embed($string,$useCache=true,$vectorOnly=true) {
        if($useCache && strlen($string) > static::maxLength()) {
            $useCache = false;
        }

        if($useCache) {   
            $embedding = static::find($string);
            if($embedding) {
                if($vectorOnly) {
                    return $embedding->vector();
                }
                return $embedding;
            }
        
        }
        $md5 = md5($string);
        $OAIEmbedding = OpenAIEmbedding::embedString($string);
        if(!$useCache && $vectorOnly) {
            return $OAIEmbedding;
        }
        $data = [
            'md5' => $md5,
            'query' => $string,
            'vector' => json_encode($OAIEmbedding,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE)
        ];
        $embedding = new static($data);
        if($useCache && !is_array($string) && strlen($string) <= static::maxLength()) {
            $embedding->save();
        }
        if($vectorOnly) {
            return $embedding->vector();
        }
        return $embedding;
    }
}