<?php

namespace Acms\Services\Form;

use Acms\Services\Facades\Application as App;
use Acms\Services\Auth\Contracts\Guard;

/**
 * フォーム機能の認可判定を集約する。
 *
 * ロール運用時は form_view / form_edit ロール、未使用時はフォーム管理セッションで判定する。
 * 各ハンドラ（ACMS_POST_Form_* / ACMS_GET_Admin_Form_*）から共通利用する。
 *
 * 判定対象のユーザーは引数で受け取り、テスト時に任意のユーザーを差し込めるようにする
 * （ロール運用の判定はユーザーを基準に行う。ロール未使用時のセッション判定は
 * アクセス中のユーザーが対象となる）。ロール判定はガード選択がセッションユーザー（SUID）
 * 基準となる Auth ファサードではなく、ロールガードを直接利用することで、
 * 引数で受け取ったユーザーを基準に評価する。
 */
class Authorization
{
    /**
     * フォームの閲覧・エクスポートが許可されているか
     *
     * @param int|null $userId 判定対象のユーザーID（通常はログイン中のユーザー SUID。未ログイン時は null）
     * @param int $blogId 対象ブログID
     * @return bool
     */
    public function canView(?int $userId, int $blogId): bool
    {
        if (roleAvailableUser($userId)) {
            $guard = $this->roleGuard();
            return $guard->roleAuthorization('form_view', $blogId, 0, $userId)
                || $guard->roleAuthorization('form_edit', $blogId, 0, $userId);
        }

        return sessionWithFormAdministration($blogId);
    }

    /**
     * フォームの編集・作成・削除・複製・インポートが許可されているか
     *
     * @param int|null $userId 判定対象のユーザーID（通常はログイン中のユーザー SUID。未ログイン時は null）
     * @param int $blogId 対象ブログID
     * @return bool
     */
    public function canEdit(?int $userId, int $blogId): bool
    {
        if (roleAvailableUser($userId)) {
            return $this->roleGuard()->roleAuthorization('form_edit', $blogId, 0, $userId);
        }

        return sessionWithFormAdministration($blogId);
    }

    /**
     * フォームの投稿ログ閲覧が許可されているか
     *
     * 閲覧系（canView）と異なり、ロール運用時は form_view 権限のみで判定する
     * （form_edit だけのユーザーにはログを開放しない）。
     *
     * @param int|null $userId 判定対象のユーザーID（通常はログイン中のユーザー SUID。未ログイン時は null）
     * @param int $blogId 対象ブログID
     * @return bool
     */
    public function canViewLog(?int $userId, int $blogId): bool
    {
        if (roleAvailableUser($userId)) {
            return $this->roleGuard()->roleAuthorization('form_view', $blogId, 0, $userId);
        }

        return sessionWithFormAdministration($blogId);
    }

    /**
     * フォームの投稿ログ削除が許可されているか
     *
     * 編集系（canEdit）と異なり、ロール未使用時はフォーム管理権限ではなく
     * ブログ管理者権限（sessionWithAdministration）を要求する。
     *
     * @param int|null $userId 判定対象のユーザーID（通常はログイン中のユーザー SUID。未ログイン時は null）
     * @param int $blogId 対象ブログID
     * @return bool
     */
    public function canDeleteLog(?int $userId, int $blogId): bool
    {
        if (roleAvailableUser($userId)) {
            return $this->roleGuard()->roleAuthorization('form_edit', $blogId, 0, $userId);
        }

        return sessionWithAdministration($blogId);
    }

    /**
     * ロールベースの権限判定ガードを取得する。
     *
     * Auth ファサードはガード選択をセッションユーザー（SUID）基準で行うため、
     * 引数で受け取ったユーザーを基準に判定するにはロールガードを直接利用する。
     * roleAvailableUser() が真のユーザーに対してのみ呼ばれるため、本番では
     * Auth ファサード経由（ロールユーザーは同じくロールガードに振られる）と同一の結果になる。
     *
     * @return \Acms\Services\Auth\Contracts\Guard
     */
    private function roleGuard(): Guard
    {
        $guard = App::make('auth.role');
        assert($guard instanceof Guard);

        return $guard;
    }
}
