<?php
/**
 * Created by Error202
 * Date: 10.07.2018
 */

namespace backend\controllers;

use core\entities\menu\Menu;
use core\entities\menu\MenuItem;
use core\entities\ModuleRecord;
use core\forms\menu\MenuForm;
use core\forms\menu\MenuItemForm;
use core\forms\menu\MenuSelectForm;
use core\services\menu\MenuItemManageService;
use core\services\menu\MenuManageService;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
use yii\helpers\Json;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use Yii;

class MenuController extends Controller
{
    public $menu_service;
    public $menu_item_service;

    public function __construct(
        string $id,
        $module,
        MenuManageService $menu_service,
        MenuItemManageService $menu_item_service,
        array $config = []
    ) {
        parent::__construct($id, $module, $config);

        $this->menu_service      = $menu_service;
        $this->menu_item_service = $menu_item_service;
    }

    public function behaviors(): array
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['MenuManagement'],
                    ],
                    [    // all the action are accessible to admin
                        'allow' => true,
                        'roles' => ['admin'],
                    ],
                ],
            ],
            'verbs'  => [
                'class'   => VerbFilter::class,
                'actions' => [
                    'delete'           => ['POST'],
                    'delete-menu-item' => ['POST'],
                ],
            ],
        ];
    }

    public function actionIndex($id = null)
    {
        $menus        = []; // menu list
        $menu_records = Menu::find()->all();
        foreach ($menu_records as $menu_record) {
            $menus[$menu_record->id] = isset($menu_record->translation) && $menu_record->translation->name ? $menu_record->translation->name : $menu_record->findTranslation(Yii::$app->params['defaultLanguage'])->name;
        }

        $form = new MenuSelectForm();
        if ($form->load(Yii::$app->request->get()) && $form->validate()) {
            return $this->redirect(['menu/index', 'id' => $form->id]);
        } elseif ($id) {
            $this->createMenuItem(); // create menu item if MenuItemForm sent

            $menu = $this->findModel($id);

            $creatorWidgets = $this->getCreatorWidgets($menu->id);

            return $this->render('menu', [
                'model'   => $form,
                'menus'   => $menus,
                'menu'    => $menu,
                'creator' => $creatorWidgets,
            ]);
        } else {
            return $this->render('select_menu', [
                'model' => $form,
                'menus' => $menus,
            ]);
        }
    }

    public function actionCreate()
    {
        $form = new MenuForm();
        if ($form->load(Yii::$app->request->post()) && $form->validate()) {
            try {
                $menu = $this->menu_service->create($form);

                return $this->redirect(['index', 'id' => $menu->id]);
            } catch (\DomainException $e) {
                Yii::$app->errorHandler->logException($e);
                Yii::$app->session->setFlash('error', $e->getMessage());
            }
        }

        return $this->render('create', [
            'model' => $form,
        ]);
    }

    public function actionUpdate($id)
    {
        $menu = $this->findModel($id);

        $form = new MenuForm($menu);
        if ($form->load(Yii::$app->request->post()) && $form->validate()) {
            try {
                $this->menu_service->edit($menu->id, $form);

                return $this->redirect(['index', 'id' => $menu->id]);
            } catch (\DomainException $e) {
                Yii::$app->errorHandler->logException($e);
                Yii::$app->session->setFlash('error', $e->getMessage());
            }
        }

        return $this->render('update', [
            'model' => $form,
            'menu'  => $menu,
        ]);
    }

    public function actionDelete($id)
    {
        try {
            $this->menu_service->remove($id);
        } catch (\DomainException $e) {
            Yii::$app->errorHandler->logException($e);
            Yii::$app->session->setFlash('error', $e->getMessage());
        }

        return $this->redirect(['index']);
    }

    public function actionSaveItem($id)
    {
        $item = $this->findItemModel($id);
        $form = new MenuItemForm($item);
        if ($form->load(Yii::$app->request->post()) && $form->validate()) {
            try {
                $this->menu_item_service->edit($item->id, $form);

                return $this->redirect(['index', 'id' => $item->menu_id]);
            } catch (\DomainException $e) {
                Yii::$app->errorHandler->logException($e);
                Yii::$app->session->setFlash('error', $e->getMessage());
            }
        }

        return $this->redirect(['index', 'id' => $item->menu_id]);
    }

    public function actionDeleteMenuItem()
    {
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        if (Yii::$app->request->isAjax) {
            try {
                $id   = Yii::$app->request->post('id');
                $item = $this->findItemModel($id);
                $item->delete();

                Yii::$app->session->setFlash('success', Yii::t('menu', 'Menu Item Deleted'));

                return ['result' => 'success'];
            } catch (\RuntimeException $e) {
                return ['result' => 'error', 'message' => $e->getMessage()];
            }
        }

        return ['result' => 'error', 'message' => 'Request error'];
    }

    public function actionSaveMenuItems()
    {
        $json                       = Yii::$app->request->post('json');
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        if (Yii::$app->request->isAjax) {
            try {
                $order = [];
                $items = Json::decode($json, true);
                foreach ($items as $item) {
                    $order[$item[1]] = isset($order[$item[1]]) ? $order[$item[1]] + 1 : 0;
                    $this->menu_item_service->setPosition($item, $order[$item[1]]);
                }
                Yii::$app->session->setFlash('success', Yii::t('menu', 'Menu Saved'));

                return ['result' => 'success'];
            } catch (\RuntimeException $e) {
                return ['result' => 'error', 'message' => $e->getMessage()];
            }
        }

        return ['result' => 'error', 'message' => 'Request error'];
    }

    private function getCreatorWidgets($menu_id): array
    {
        $widgets = [];
        $modules = ModuleRecord::find()->active()->all();
        foreach ($modules as $module) {
            if (method_exists($module->class, 'getMenuItemCreator')) {
                $module_widgets = call_user_func_array($module->class . '::getMenuItemCreator', [$menu_id]);
                $widgets        = is_array($module_widgets) ? array_merge($widgets, $module_widgets) : $widgets;
            }
        }

        return $widgets;
    }

    private function createMenuItem()
    {
        $form = new MenuItemForm();
        if ($form->load(Yii::$app->request->post()) && $form->validate()) {
            try {
                $this->menu_item_service->create($form);
            } catch (\DomainException $e) {
                Yii::$app->errorHandler->logException($e);
            }
        }
    }

    protected function findModel($id): Menu
    {
        if (($model = Menu::findOne($id)) !== null) {
            return $model;
        }
        throw new NotFoundHttpException('The requested menu does not exist.');
    }

    protected function findItemModel($id): MenuItem
    {
        if (($model = MenuItem::findOne($id)) !== null) {
            return $model;
        }
        throw new NotFoundHttpException('The requested menu item does not exist.');
    }
}