<?php

namespace onespace\tools\activeApi\helpers;

use Yii;
use yii\helpers\ArrayHelper;
use yii\web\Response;

/**
 * A set of basic CRUD endpoints. Should be used with `onespace\tools\components\clients\BaseOneSpaceClient` clients
 * and active API Models.
 *
 * Each of the public methods here can and should be overwritten in the parent controller.
 *
 * @author  Gareth Palmer <gareth@one-space.co.za>
 */

trait CrudControllerHelperTrait {
    use RestControllerHelperTrait;


    /**
     * Contains the class of the main model used by the controller.
     *
     * Should be passed as `MyModel::class`
     *
     * @var string  $modelClass
     *
     * @access  private
     */

    private string $modelClass;

    /**
     * Required for the user to set and return the main Model class.
     *
     * Should be something like:
     *
     * ```php
     * public function modelClass(): string {
     *  return MyModel::class;
     * }
     * ```
     *
     * @return  string  The full class name returned my `::class`.
     *
     * @access  public
     */
    abstract public function modelClass(): string;

    /**
     * Returns the main Model class used by the controller.
     *
     * @return  string
     *
     * @access  public
     */
    protected function getModelClass(): string {
        if (!isset($this->modelClass)) {
            $this->modelClass = $this->modelClass();
        }
        return $this->modelClass;
    }

    /**
     * The basic `Select Records` type query endpoint.
     *
     * @return  yii\web\Response
     *
     * @access  public
     */
    public function actionView(): Response {
        Yii::info(Yii::$app->request->get(), __METHOD__);

        $modelClass = $this->getModelClass();

        list($params, $sort, $offset, $limit, $with) = $this->getRequestProperties();

        $query = $modelClass::find();

        Yii::info($params, __METHOD__);

        $this->applyWhere($query, $params);

        $this->applyWith($query, $with);

        $total = $query->count();

        Yii::debug("Total: " . $total, __METHOD__);

        $this->applySort($query, $sort);
        $this->applyLimitAndOffset($query, $limit, $offset);

        $data = $query->all();

        Yii::info([
            'success' => true,
            'total' => $total,
            'data' => ArrayHelper::toArray($data),
            'sort' => $sort,
            'offset' => $offset,
            'limit' => $limit,
        ], __METHOD__);

        return $this->asJson([
            'success' => true,
            'total' => $total,
            'data' => $data,
            'sort' => $sort,
            'offset' => $offset,
            'limit' => $limit,
        ]);
    }

    /**
     * The basic `Create Record` API endpoint.
     *
     * @return  yii\web\Response
     *
     * @access  public
     */
    public function actionCreate(): Response {
        Yii::info(Yii::$app->request->post(), __METHOD__);

        $modelClass = $this->getModelClass();

        /** @var \yii\db\ActiveRecord $model */
        $model = new $modelClass();

        $post = Yii::$app->request->post();

        // returns flat list of db columns
        $attributes = $model->attributes();
        // Yii::info("Attributes: " . json_encode($attributes), __METHOD__);

        foreach ($post as $key => $value) {
            if (in_array($key, $attributes)) {
                $model->$key = $value;
            }
        }

        $success = $model->save();
        $data = $success ? ArrayHelper::toArray($model) : $model->getErrors();

        Yii::info([
            'success' => $success,
            'data' => $data,
        ], __METHOD__);

        return $this->asJson([
            'success' => $success,
            'data' => $data,
        ]);
    }

    /**
     * The basic `Update Record` API endpoint.
     *
     * @return  yii\web\Response
     *
     * @access  public
     */
    public function actionUpdate(): Response {
        Yii::info(Yii::$app->request->post(), __METHOD__);

        $modelClass = $this->getModelClass();

        /** @var \yii\db\ActiveRecord $model */
        $model = $modelClass::findOne(Yii::$app->request->post('where'));
        if ($model === null) {
            return $this->customErrorResponse(404, "No records found");
        }

        $post = Yii::$app->request->post('set');

        // returns flat list of db columns
        $attributes = $model->attributes();
        // Yii::info("Attributes: " . json_encode($attributes), __METHOD__);

        foreach ($post as $key => $value) {
            if (in_array($key, $attributes)) {
                $model->$key = $value;
            }
        }

        $success = $model->save();
        $data = $success ? ArrayHelper::toArray($model) : $model->getErrors();

        Yii::info([
            'success' => $success,
            'data' => $data,
        ], __METHOD__);

        return $this->asJson([
            'success' => $success,
            'data' => $data,
        ]);
    }

    /**
     * The basic `Delete Record` API endpoint.
     *
     * @return  yii\web\Response
     *
     * @access  public
     */
    public function actionDelete(): Response {
        Yii::info(Yii::$app->request->post(), __METHOD__);

        $modelClass = $this->getModelClass();

        $model = $modelClass::findOne(Yii::$app->request->post());
        if ($model === null) {
            return $this->customErrorResponse(404, "No group found");
        }

        $key = $model->getPrimaryKey();
        $del = $model->delete();
        $success = $del !== false && $del > 0;

        $data = $success ? "Entry: {$key} successfully deleted" : json_encode($model->getErrors());

        Yii::info([
            'success' => $success,
            'data' => $data,
        ], __METHOD__);

        return $this->asJson([
            'success' => $success,
            'data' => $data,
        ]);
    }
}
