<?php

namespace App\Traits\Model;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

trait Basic
{
    public static function toggle($id, $field = 'active')
    {
        return self::update([$field => ! self::getField($id, $field)], $id);
    }

    public static function getIDs()
    {
        return self::getAll()->pluck('id');
    }

    public static function getOptions($field = 'name')
    {
        $data = self::getModel()->pluck($field, 'id')->toArray();
        asort($data, SORT_NATURAL | SORT_FLAG_CASE);

        return $data;
    }

    public static function getName($id, $len = false)
    {
        $name = self::getField($id, 'name');

        return $len ? Str::limit($name, $len) : $name;
    }

    public static function getUUID($id)
    {
        return self::getField($id, 'uuid');
    }

    public static function getByUUID($uuid, $relations = [])
    {
        return self::getByField('uuid', $uuid, $relations)->first();
    }

    public static function getIdByUUID($uuid)
    {
        $model = self::getByUUID($uuid);

        return $model ? $model->id : false;
    }

    public static function generateToken()
    {
        return Hash::make(self::generateUUID());
    }

    public static function generateUUID()
    {
        return Str::uuid()->toString();
    }

    public static function getFields($field)
    {
        return self::getAll()->pluck($field);
    }

    public static function getByField($field, $value, $relations = [])
    {
        return self::getModel()->with($relations)->where($field, $value)->get();
    }

    public static function getField($id, $field)
    {
        $model = self::get($id);

        return $model ? $model->$field : false;
    }

    public static function edit($id)
    {
        return self::getArray($id);
    }

    public static function store($data, $stopStamping = false)
    {
        return $data['id'] ?? false ? self::update($data, false, $stopStamping) : self::create($data, $stopStamping);
    }

    public static function create($data, $stopStamping = false)
    {
        return self::getModel($stopStamping)->create($data);
    }

    public static function update($data, $id = false, $stopStamping = false)
    {
        $id = $id ? $id : $data['id'];
        $model = self::get($id);
        if ($stopStamping) {
            $model->stopUserstamping();
        }
        $model->update($data);

        return $model;
    }

    public static function destroy($id, $force = false)
    {
        $model = self::get($id);

        if ($model) {
            return $force ? $model->forceDelete() : $model->delete();
        }

        return false;
    }

    public static function count()
    {
        return self::getModel()->count();
    }

    public static function firstOrCreate($search, $data = false)
    {
        return self::getModel()->firstOrCreate($search, $data ? $data : $search);
    }

    public static function deleteByField($field, $value)
    {
        $model = self::getModel()->where($field, $value);

        return $model ? $model->delete() : false;
    }

    public static function getArray($id, $relations = false, $relationsCount = false)
    {
        $model = self::get($id, $relations, $relationsCount);

        return $model ? $model->toArray() : false;
    }

    public static function get($id, $relations = false, $relationsCount = false)
    {
        return self::getModelRelations($relations, $relationsCount)->find($id);
    }

    public static function getWithTrashed($id, $relations = false, $relationsCount = false)
    {
        return self::getModelRelations($relations, $relationsCount)->withTrashed()->find($id);
    }

    public static function getAllArray($relations = false, $relationsCount = false)
    {
        return self::getAll($relations, $relationsCount)->toArray();
    }

    public static function getAll($relations = false, $relationsCount = false)
    {
        return self::getModelRelations($relations, $relationsCount)->get();
    }

    public static function getRevisions($id)
    {
        $model = self::get($id, ['revisions.user'])->toArray();

        return collect($model['revisions'])->sortBy('created_at')->reverse()->toArray();
    }

    public static function getModelRelations($relations = false, $relationsCount = false)
    {
        $model = $relations ? self::getModelWithRelations($relations) : false;
        $model = $relationsCount ? self::getModelWithCountRelations($relationsCount, $model) : $model;

        return $model ? $model : self::getModel();
    }

    public static function getModelWithRelations($relations = false, $model = false)
    {
        return is_object($model) ? $model->with($relations) : self::getModel()->with($relations);
    }

    public static function getModelWithCountRelations($relations = false, $model = false)
    {
        return is_object($model) ? $model->withCount($relations) : self::getModel()->withCount($relations);
    }

    public static function getModel($stopStamping = false): Model
    {
        $model = new Model();
        if ($stopStamping) {
            $model->stopUserstamping();
        }

        return $model;
    }
}
