<?php

namespace Acms\Services\Auth;

use DB;
use SQL;
use ACMS_Filter;
use ACMS_RAM;
use Acms\Services\Facades\Application;
use Acms\Services\Facades\Config;

class General implements Contracts\Guard
{
    /**
     * 指定ユーザーが読者か
     *
     * @param int|null $uid
     * @return bool
     */
    public function isSubscriber($uid = SUID)
    {
        if (!$uid) {
            return false;
        }
        return 'subscriber' === ACMS_RAM::userAuth($uid);
    }

    /**
     * 指定したユーザーが投稿者か
     *
     * @param int|null $uid
     * @return bool
     */
    public function isContributor($uid = SUID)
    {
        if (!$uid) {
            return false;
        }
        return 'contributor' === ACMS_RAM::userAuth($uid);
    }

    /**
     * 指定したユーザーが編集者か
     *
     * @param int|null $uid
     * @return bool
     */
    public function isEditor($uid = SUID)
    {
        if (!$uid) {
            return false;
        }
        return 'editor' === ACMS_RAM::userAuth($uid);
    }

    /**
     * 指定したユーザーが管理者か
     *
     * @param int|null $uid
     * @return bool
     */
    public function isAdministrator($uid = SUID)
    {
        if (!$uid) {
            return false;
        }
        return 'administrator' === ACMS_RAM::userAuth($uid);
    }

    /**
     * 指定したユーザーがそのブログにおいて読者以上の権限があるか
     *
     * @param int|null $blogId
     * @param int|null $userId
     * @return bool
     */
    public function isPermissionOfSubscriber($blogId = BID, $userId = SUID)
    {
        if (!$this->isControlBlog($blogId, $userId)) {
            return false;
        }

        switch (ACMS_RAM::userAuth($userId)) {
            case 'administrator':
            case 'editor':
            case 'contributor':
            case 'subscriber':
                break;
            default:
                return false;
        }
        return true;
    }

    /**
     * 指定したユーザーがそのブログにおいて投稿者以上の権限があるか
     *
     * @param int|null $blogId
     * @param int|null $userId
     * @return bool
     */
    public function isPermissionOfContributor($blogId = BID, $userId = SUID)
    {
        if (!$this->isControlBlog($blogId, $userId)) {
            return false;
        }

        switch (ACMS_RAM::userAuth($userId)) {
            case 'administrator':
            case 'editor':
            case 'contributor':
                break;
            default:
                return false;
        }
        return true;
    }

    /**
     * 指定したユーザーがそのブログにおいて編集者以上の権限があるか
     *
     * @param int|null $blogId
     * @param int|null $userId
     * @return bool
     */
    public function isPermissionOfEditor($blogId = BID, $userId = SUID)
    {
        if (!$this->isControlBlog($blogId, $userId)) {
            return false;
        }
        switch (ACMS_RAM::userAuth($userId)) {
            case 'administrator':
            case 'editor':
                break;
            default:
                return false;
        }
        return true;
    }

    /**
     * 指定したユーザーがそのブログにおいて管理者以上の権限があるか
     *
     * @param int|null $blogId
     * @param int|null $userId
     * @return bool
     */
    public function isPermissionOfAdministrator($blogId = BID, $userId = SUID)
    {
        if (!$this->isControlBlog($blogId, $userId)) {
            return false;
        }
        return $this->isAdministrator($userId);
    }

    /**
     * 指定したユーザーがSNSログインを利用できるか
     *
     * @param int|null $uid
     * @param int|null $bid
     * @return bool
     */
    public function isPermissionOfSnsLogin($uid = SUID, $bid = BID)
    {
        $Config = Config::loadBlogConfigSet($bid);

        if ($Config->get('snslogin') !== 'on') {
            return false;
        }
        $auth = ACMS_RAM::userAuth($uid);

        switch ($Config->get('snslogin_auth')) {
            case 'subscriber':
                if (in_array($auth, ['contributor', 'editor', 'administrator'], true)) {
                    return false;
                }
                break;
            case 'contributor':
                if (in_array($auth, ['editor', 'administrator'], true)) {
                    return false;
                }
                break;
            case 'editor':
                if (in_array($auth, ['administrator'], true)) {
                    return false;
                }
                break;
            case 'administrator':
                break;
            default:
                return false;
        }
        return true;
    }

    /**
     * @inheritDoc
     */
    public function checkShortcut(array $ids, ?int $userId = SUID): bool
    {
        /** @var \Acms\Services\Shortcut\Helper $ShortcutService */
        $ShortcutService = Application::make('shortcut.helper');
        return $ShortcutService->authorization(ADMIN, $ids, BID, $userId);
    }

    /**
     * 指定したユーザーがそのブログにおいて権限があるか
     *
     * $userId が既定値（SUID、ログイン中のユーザー）の場合は、ログイン時点で固定される
     * SBID を使う（既存呼び出し全ての挙動を変えないため）。それ以外の任意の $userId を
     * 渡された場合のみ、そのユーザーの所属ブログを ACMS_RAM 経由で都度取得する。
     *
     * @param int|null $blogId
     * @param int|null $userId
     * @return bool
     */
    public function isControlBlog($blogId, $userId = SUID)
    {
        if (!$userId) {
            return false;
        }

        $userBlogId = ($userId === SUID) ? SBID : ACMS_RAM::userBlog($userId);

        if (
            1
            and ACMS_RAM::userGlobalAuth($userId) !== 'on'
            and $userBlogId !== intval($blogId)
        ) {
            return false;
        }

        if (
            !(1
            and ACMS_RAM::blogLeft($userBlogId) <= ACMS_RAM::blogLeft($blogId)
            and ACMS_RAM::blogRight($userBlogId) >= ACMS_RAM::blogRight($blogId)
            )
        ) {
            return false;
        }

        return true;
    }

    /**
     * 指定したユーザーの権限があるブログリストを取得
     *
     * @param int $uid
     * @return array
     */
    public function getAuthorizedBlog($uid)
    {
        if (ACMS_RAM::userGlobalAuth($uid) !== 'on') {
            return [ACMS_RAM::userBlog($uid)];
        }
        $SQL = SQL::newSelect('blog');
        $SQL->setSelect('blog_id');
        ACMS_Filter::blogTree($SQL, ACMS_RAM::userBlog($uid), 'self-descendant');
        if (!$this->isAdministrator($uid)) {
            $SQL->addWhereOpr('blog_status', 'close', '<>');
        }
        return DB::query($SQL->get(dsn()), 'list');
    }

    /**
     * @inheritDoc
     */
    public function roleAuthorization($action, $bid = BID, $eid = 0, $uid = SUID)
    {
        return false;
    }
}
