<?php

namespace apexl\Io\operators;

use apexl\entityCore\interfaces\EntityOperatorInterface;
use apexl\Vault\Vault;

class entityDatabaseOperator implements EntityOperatorInterface{
    /** @var Vault  */
    protected $vault;
    protected $dbTable;
    protected $primaryKey;

    public function __construct($table, $primaryKey = 'id'){
        $this->vault = Vault::getInstance();
        $this->dbTable = $table;
        $this->setPrimaryKey($primaryKey);
    }

    public function setPrimaryKey($key){
        $this->primaryKey = $key;
        return $this;
    }

    public function load($id){
        $entity = $this->vault->select($this->dbTable)->fields()->where($this->primaryKey, $id)->execute()->fetchAssoc();
        return ['updateEntityData' => true, 'data' => $entity];
    }

    public function loadMultiple($conditions = [], $orderBy = [], $limit = FALSE, $offset = FALSE){
        $query = $this->vault->select($this->dbTable)->fields();
        foreach($conditions as $condition){
            $operator = $condition[2] ?? '=';
            $type = $condition[3] ?? 'AND';
            $postCondition = $condition[4] ?? '';
            $query->where($condition[0], $condition[1], $operator, $type, $postCondition);
        }
        if(!empty($orderBy)){
            $direction = $orderBy[1] ?? 'DESC';
            $query->orderBy($orderBy[0], $direction);
        }
        if($limit !== FALSE){
            $query->limit($limit, $offset);
        }
        return $query->execute()->fetchAll();
    }

    public function totalEntities(){
        $result = $this->vault->select($this->dbTable)->fields('count('.$this->primaryKey.') AS count')->execute()->fetchAssoc();
        return $result['count'];
    }

    public function store($data){
        //first, are we inserting or updating
        if(empty($data)){
            throw new \Exception("Cannot store empty entity data");
        }
        $entity = [];
        if(isset($data[$this->primaryKey]) && !empty($data[$this->primaryKey])) {
            $entity = $this->load($data[$this->primaryKey]);
        }
        if (isset($entity['data']) && !empty($entity['data'])) {
            //not empty? we have a record, so update.
            $this->vault->update($this->dbTable)->fields($data)->where($this->primaryKey, $data[$this->primaryKey])->execute();
            return TRUE;
        } else {
            //we're inserting to force an entity update in case we have a new primary key.
            $this->vault->insert($this->dbTable)->fields($data)->execute();
            $lastStored = $this->getLastNewRecord();
            //force the local entity to be updated with the new data (id etc)
            return ['updateEntityData' => true, 'data' => $this->load($lastStored[$this->primaryKey])['data']];
        }
    }

    public function getLastNewRecord(){
        return $this->vault->select($this->dbTable)->fields()->orderBy($this->primaryKey, 'DESC')->execute()->fetchAssoc();
    }

    public function delete($id){
        return $this->vault->delete($this->dbTable)->where($this->primaryKey, $id)->execute();
    }

    public function loadAll(){
        return $this->vault->select($this->dbTable)->execute()->fetchAll();
    }

    public function getTableColumns(){
        return $this->vault->describe($this->dbTable)->execute()->fetchAll();
    }
}