<?php

namespace Filanco\Cms;

use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Filanco\Cms\FormFields\After\HandlerInterface as AfterHandlerInterface;
use Filanco\Cms\FormFields\HandlerInterface;
use Filanco\Cms\Models\Category;
use Filanco\Cms\Models\DataRow;
use Filanco\Cms\Models\DataType;
use Filanco\Cms\Models\Menu;
use Filanco\Cms\Models\MenuItem;
use Filanco\Cms\Models\Page;
use Filanco\Cms\Models\Permission;
use Filanco\Cms\Models\Post;
use Filanco\Cms\Models\Role;
use Filanco\Cms\Models\Setting;
use Filanco\Cms\Models\User;
use Filanco\Cms\Traits\Translatable;

class Cms
{
    protected $version;
    protected $filesystem;

    protected $alerts = [];
    protected $alertsCollected = false;

    protected $formFields = [];
    protected $afterFormFields = [];

    protected $permissionsLoaded = false;
    protected $permissions = [];

    protected $users = [];

    protected $models = [
        'Category'   => Category::class,
        'DataRow'    => DataRow::class,
        'DataType'   => DataType::class,
        'Menu'       => Menu::class,
        'MenuItem'   => MenuItem::class,
        'Page'       => Page::class,
        'Permission' => Permission::class,
        'Post'       => Post::class,
        'Role'       => Role::class,
        'Setting'    => Setting::class,
        'User'       => User::class,
    ];
    protected $count=array();

    public function __construct()
    {
        $this->filesystem = app(Filesystem::class);

        $this->findVersion();
    }

    public function model($name)
    {
        return app($this->models[studly_case($name)]);
    }

    public function modelClass($name)
    {
        return $this->models[$name];
    }

    public function useModel($name, $object)
    {
        if (is_string($object)) {
            $object = app($object);
        }

        $class = get_class($object);

        if (isset($this->models[studly_case($name)]) && !$object instanceof $this->models[studly_case($name)]) {
            throw new \Exception("[{$class}] must be instance of [{$this->models[studly_case($name)]}].");
        }

        $this->models[studly_case($name)] = $class;

        return $this;
    }

    public function formField($row, $dateType, $dataTypeContent)
    {
        $formField = $this->formFields[$row->type];

        return $formField->handle($row, $dateType, $dataTypeContent);
    }

    public function afterFormFields($row, $dataType, $dataTypeContent)
    {
        $options = json_decode($row->details);

        return collect($this->afterFormFields)->filter(function ($after) use ($row, $dataType, $dataTypeContent, $options) {
            return $after->visible($row, $dataType, $dataTypeContent, $options);
        });
    }

    public function addFormField($handler)
    {
        if (!$handler instanceof HandlerInterface) {
            $handler = app($handler);
        }

        $this->formFields[$handler->getCodename()] = $handler;

        return $this;
    }

    public function addAfterFormField($handler)
    {
        if (!$handler instanceof AfterHandlerInterface) {
            $handler = app($handler);
        }

        $this->afterFormFields[$handler->getCodename()] = $handler;

        return $this;
    }

    public function formFields()
    {
        $connection = config('database.default');
        $driver = config("database.connections.{$connection}.driver", 'mysql');

        return collect($this->formFields)->filter(function ($after) use ($driver) {
            return $after->supports($driver);
        });
    }

    public function setting($key, $default = null)
    {
        $setting = Setting::where('key', '=', $key)->first();

        if (isset($setting->id)) {
            return $setting->value;
        }

        return $default;
    }

    public function image($file, $default = '')
    {
        if (!empty($file) && Storage::disk(config('Cms.storage.disk'))->exists($file)) {
            return Storage::disk(config('Cms.storage.disk'))->url($file);
        }

        return $default;
    }

    public function routes()
    {
        require __DIR__.'/../routes/Cms.php';
    }

    public function can($permission)
    {
        $this->loadPermissions();

        // Check if permission exist
        $exist = $this->permissions->where('key', $permission)->first();

        if ($exist) {
            $user = $this->getUser();
            if ($user == null || !$user->hasPermission($permission)) {
                return false;
            }

            return true;
        }

        return true;
    }

    public function canOrFail($permission)
    {
        if (!$this->can($permission)) {
            throw new UnauthorizedHttpException(null);
        }

        return true;
    }

    public function canOrAbort($permission, $statusCode = 403)
    {
        if (!$this->can($permission)) {
            return abort($statusCode);
        }

        return true;
    }

    public function getVersion()
    {
        return $this->version;
    }

    public function addAlert(Alert $alert)
    {
        $this->alerts[] = $alert;
    }

    public function alerts()
    {
        if (!$this->alertsCollected) {
            event('Cms.alerts.collecting');

            $this->alertsCollected = true;
        }

        return $this->alerts;
    }

    protected function findVersion()
    {
        if (!is_null($this->version)) {
            return;
        }

        if ($this->filesystem->exists(base_path('composer.lock'))) {
            // Get the composer.lock file
            $file = json_decode(
                $this->filesystem->get(base_path('composer.lock'))
            );

            // Loop through all the packages and get the version of Cms
            foreach ($file->packages as $package) {
                if ($package->name == 'filanco/cms') {
                    $this->version = $package->version;
                    break;
                }
            }
        }
    }

    public function getCount($name)
    {
        if(!isset($this->count[$name])){
            $this->count[$name]=1;
            return true;
        }else{
            return false;
        }


    }



    /**
     * @param string|Model|Collection $model
     *
     * @return bool
     */




    public function translatable($model)
    {

        if (!config('Cms.multilingual.bread')) {
            return false;
        }

        if (is_string($model)) {
            $model = app($model);
        }

        if ($model instanceof Collection) {
            $model = $model->first();
        }

        if (!is_subclass_of($model, Model::class)) {
            return false;
        }

        $traits = class_uses_recursive(get_class($model));

        return in_array(Translatable::class, $traits);
    }

    protected function loadPermissions()
    {
        if (!$this->permissionsLoaded) {
            $this->permissionsLoaded = true;

            $this->permissions = Permission::all();
        }
    }

    protected function getUser($id = null)
    {
        if (is_null($id)) {
            $id = auth()->check() ? auth()->user()->id : null;
        }

        if (is_null($id)) {
            return;
        }

        if (!isset($this->users[$id])) {
            $this->users[$id] = User::find($id);
        }

        return $this->users[$id];
    }
}
