<?php

namespace Ignite\Core\Repositories;

use Ignite\Core\Models\Menu\PageItem;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Ignite\Core\Contracts\Repositories\PageRepository as PageRepositoryInterface;
use Ignite\Core\Entities\Page;

class PageRepository implements PageRepositoryInterface
{
    /**
     * The default raw query builder object.
     *
     * @return Builder
     */
    public function findRaw()
    {
        return Page::query();
    }

    /**
     * Find all pages.
     *
     * @param  int $limit
     *
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|\Illuminate\Database\Eloquent\Collection
     */
    public function findAll($limit = null)
    {
        if (is_null($limit)) {
            return $this->findRaw()->get();
        }

        return $this->findRaw()->paginate($limit);
    }

    /**
     * Find one page by primary key.
     *
     * @param  int $id
     * @return Page
     */
    public function find($id)
    {
        return Page::findOrFail($id);
    }

    /**
     * Find one page by primary key.
     *
     * @param  int $code
     * @return Page
     */
    public function findByCode($code)
    {
        return $this->findRaw()
            ->byCode($code)
            ->onlyActive()
            ->onlyPublished()
            ->first();
    }

    /**
     * Find the homepage.
     *
     * @return Page
     */
    public function findHomepage()
    {
        return $this->findRaw()
            ->isHome()
            ->first();
    }

    /**
     * Find the pages for the navigation.
     *
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function findForNavigation()
    {
        return $this->findRaw()
            ->onlyVisibleInMenu()
            ->onlyActive()
            ->onlyPublished()
            ->get()
            ->mapInto(PageItem::class);
    }

    /**
     * Create a new page.
     *
     * @param  array $data
     * @return mixed
     */
    public function create(array $data)
    {
        return Page::create($data);
    }

    /**
     * Update a page using the id to locate it.
     *
     * @param  int $id
     * @param  array $data
     * @return bool
     */
    public function update($id, array $data)
    {
        $page = $this->find($id);

        $page->fill($data);

        return $page->save();
    }

    /**
     * Reorder the position of pages in the front-end menu.
     *
     * @param  array $positions
     * @return \Illuminate\Support\Collection
     */
    public function reorder(array $positions)
    {
        DB::transaction(function () use ($positions) {
            foreach ($positions as $record) {
                DB::table('core_page')->where('id', $record['id'])->update(['position' => $record['position']]);
            }
        });

        return $positions;
    }

    /**
     * Toggle a field on a resource.
     *
     * @param  int $id
     * @param  string $name
     * @param  string $value
     * @return bool
     * @throws \Exception
     */
    public function toggle($id, $name, $value)
    {
        $page = $this->find($id);

        if ($page->isAlias()) {
            throw new \DomainException(
                'You cannot toggle attributes on an aliased page.'
            );
        }

        $value = $page->toggleAttribute($name, $value);
        $this->update($id, [
            $name => $value
        ]);

        return $value;
    }
}
