<?php

namespace Fivable\Buildable\Models;

use Fivable\Buildable\Traits\HasMetas;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;

class BuildableMenu extends Model
{
    use SoftDeletes, HasMetas;

    /* Columns that are mass-assignable */
    protected $fillable = ['type', 'content'];
    /* Columns to convert to Carbon */
    protected $dates = ['created_at', 'updated_at', 'deleted_at'];
    /* Columns to cast */
    protected $casts = ['content' => 'array'];

    /** Relationships
     * ----------------*/

    /**
     * Get the root BuildablePage for this Menu (applies to inner nav only, returns NULL otherwise)
     * @return BelongsTo
     */
    public function rootPage()
    {
        return $this->belongsTo('Fivable\Buildable\Models\BuildablePage', 'page_id');
    }

    /**
     * Return a collection of BuildablePages that have this BuildableMenu if it is type 'inner_nav'
     * @return Builder or NULL
     */
    public function innerNavPages() : ?Builder
    {
        return ($this->type == 'inner_nav') ? BuildablePage::where('inner_nav_id', $this->id) : NULL;
    }


    /** CRUD Helpers
     * ----------------*/

    /**
     * Create new BuildableMenus and save their metas
     * @param array $menuInfo
     * @return mixed
     */
    public static function createMenus(array $menuInfo) : BuildableMenu
    {
        $newMenus = [];

        foreach ($menuInfo['menus'] as $menu) {
            $newMenu = static::create($menu);
            $newMenu->saveMetas($menu['metas']);

            if ($newMenu->type == 'inner_nav') {
                foreach ($menuInfo['content'] as $page) {
                    if (!is_null($page['id'])) {
                        BuildablePage::where('id', $page['id'])->update([
                            'inner_nav_id' => $newMenu->id,
                        ]);
                    }
                }
            }

            array_push($newMenus, $newMenu);
        }

        return $newMenus;
    }

    /**
     * Update existing BuildableMenus and their metas
     * @param array $menuInfo
     * @return \stdClass
     */
    public static function updateMenus(array $menuInfo) : \stdClass
    {
        $buildableMenus = new \stdClass;
        $buildableMenus->updatedMenus = [];
        $buildableMenus->newMenus = [];

        foreach ($menuInfo['menus'] as $menu) {

            if (isset($menu['id'])) {
                $existingMenu = BuildableMenu::find($menu['id']);

                $existingMenu->update($menu);
                $existingMenu->updateMetas($menu['metas']);

                if ($existingMenu->type == 'inner_nav') {
                    foreach ($menu['removed_pages'] as $pageId) {
                        BuildablePage::where('id', $pageId)->update([
                            'inner_nav_id' => NULL,
                        ]);
                    }
                    foreach ($menu['content'] as $page) {
                        if (!is_null($page['id'])) {
                            BuildablePage::where('id', $page['id'])->update([
                                'inner_nav_id' => $existingMenu->id,
                            ]);
                        }
                    }
                }

                array_push($buildableMenus->updatedMenus, $existingMenu);
            } else {
                $newMenu = static::create($menu);
                $newMenu->saveMetas($menu['metas']);

                if ($newMenu->type == 'inner_nav') {
                    foreach ($menu['content'] as $page) {
                        if (!is_null($page['id'])) {
                            BuildablePage::where('id', $page['id'])->update([
                                'inner_nav_id' => $newMenu->id,
                            ]);
                        }
                    }
                }

                array_push($buildableMenus->newMenus, $newMenu);
            }

        }

        foreach ($menuInfo['deleted_menus'] as $deletedMenuId) {
            $menuToDelete = BuildableMenu::find($deletedMenuId);
            $menuToDelete->delete();
        }

        return $buildableMenus;
    }

    /**
     * Remove pages that reference this if type is 'inner_nav', then delete
     * @throws \Exception
     */
    public function delete()
    {
        if ($this->type == 'inner_nav') {
            $this->innerNavPages()->update(['inner_nav_id' => NULL]);
        }
        parent::delete();
    }

}
