<?php

namespace App\Helpers;

use App\Album;
use App\AlbumDefaultAnonymousPermission;
use App\AlbumDefaultGroupPermission;
use App\AlbumDefaultUserPermission;
use App\Permission;
use App\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class PermissionsHelper
{
    public function getAlbumIDs($permission = 'list', User $user = null)
    {
        $result = [];

        // First check if the anonymous user can do what is being requested - if so, the permission would also inherit
        // to logged-in users
        $anonymousUsersCan = DB::table('album_permissions_cache')
            ->join('permissions', 'permissions.id', '=', 'album_permissions_cache.permission_id')
            ->where([
                ['album_permissions_cache.user_id', null],
                ['permissions.section', 'album'],
                ['permissions.description', $permission]
            ])
            ->select('album_permissions_cache.album_id')
            ->distinct()
            ->get();

        foreach ($anonymousUsersCan as $item)
        {
            $result[] = $item->album_id;
        }

        $query = DB::table('album_permissions_cache')
            ->join('permissions', 'permissions.id', '=', 'album_permissions_cache.permission_id')
            ->where([
                ['album_permissions_cache.user_id', (is_null($user) || $user->isAnonymous() ? null : $user->id)],
                ['permissions.section', 'album'],
                ['permissions.description', $permission]
            ])
            ->select('album_permissions_cache.album_id')
            ->distinct()
            ->get();

        foreach ($query as $item)
        {
            if (!in_array($item->album_id, $result))
            {
                $result[] = $item->album_id;
            }
        }

        return $result;
    }

    public function rebuildCache()
    {
        $this->rebuildAlbumCache();
    }

    public function userCan_Album(Album $album, User $user, $permission)
    {
        // First check if the anonymous user can do what is being requested - if so, the permission would also inherit
        // to logged-in users
        $anonymousUsersCan = DB::table('album_permissions_cache')
                ->join('permissions', 'permissions.id', '=', 'album_permissions_cache.permission_id')
                ->where([
                    ['album_permissions_cache.album_id', $album->id],
                    ['album_permissions_cache.user_id', null],
                    ['permissions.section', 'album'],
                    ['permissions.description', $permission]
                ])
                ->count() > 0;

        if ($anonymousUsersCan)
        {
            return true;
        }

        return DB::table('album_permissions_cache')
            ->join('permissions', 'permissions.id', '=', 'album_permissions_cache.permission_id')
            ->where([
                ['album_permissions_cache.album_id', $album->id],
                ['album_permissions_cache.user_id', (is_null($user) || $user->isAnonymous() ? null : $user->id)],
                ['permissions.section', 'album'],
                ['permissions.description', $permission]
            ])
            ->count() > 0;
    }

    public function usersWhoCan_Album(Album $album, $permission)
    {
        $users = DB::table('album_permissions_cache')
                ->join('permissions', 'permissions.id', '=', 'album_permissions_cache.permission_id')
                ->where([
                    ['album_permissions_cache.album_id', $album->id],
                    ['permissions.section', 'album'],
                    ['permissions.description', $permission]
                ])
                ->get();

        // Include the album's owner (who can do everything)
        $users->push($album->user);

        return $users;
    }

    private function rebuildAlbumCache()
    {
        // Get a list of albums
        $albums = Album::all();

        // Get a list of all configured permissions
        $albumUserPermissions = DB::table('album_user_permissions')->get();
        $albumGroupPermissions = DB::table('album_group_permissions')->get();
        $albumAnonPermissions = DB::table('album_anonymous_permissions')->get();

        $defaultAlbumUserPermissions = AlbumDefaultUserPermission::all();
        $defaultAlbumGroupPermissions = AlbumDefaultGroupPermission::all();
        $defaultAnonPermissions = AlbumDefaultAnonymousPermission::all();

        // Get a list of all user->group memberships
        $userGroups = DB::table('user_groups')->get();

        // Build a matrix of new permissions
        $permissionsCache = [];

        /** @var Album $album */
        foreach ($albums as $album)
        {
            $effectiveAlbumID = $album->effectiveAlbumIDForPermissions();

            if ($effectiveAlbumID === 0)
            {
                /* Use the default permissions list */

                foreach ($defaultAnonPermissions as $anonymousPermission)
                {
                    $permissionsCache[] = [
                        'album_id' => $album->id,
                        'permission_id' => $anonymousPermission->permission_id,
                        'created_at' => new \DateTime(),
                        'updated_at' => new \DateTime()
                    ];
                }

                foreach ($defaultAlbumUserPermissions as $userPermission)
                {
                    $permissionsCache[] = [
                        'user_id' => $userPermission->user_id,
                        'album_id' => $album->id,
                        'permission_id' => $userPermission->permission_id,
                        'created_at' => new \DateTime(),
                        'updated_at' => new \DateTime()
                    ];
                }

                foreach ($defaultAlbumGroupPermissions as $groupPermission)
                {
                    // Get a list of users in this group, and add one per user
                    $usersInGroup = array_filter($userGroups->toArray(), function ($item) use ($groupPermission)
                    {
                        return $item->group_id = $groupPermission->group_id;
                    });

                    foreach ($usersInGroup as $userGroup)
                    {
                        $permissionsCache[] = [
                            'user_id' => $userGroup->user_id,
                            'album_id' => $album->id,
                            'permission_id' => $groupPermission->permission_id,
                            'created_at' => new \DateTime(),
                            'updated_at' => new \DateTime()
                        ];
                    }
                }
            }
            else
            {
                /* Use the specified album-specific permissions */
                $anonymousPermissions = array_filter($albumAnonPermissions->toArray(), function ($item) use ($effectiveAlbumID)
                {
                    return ($item->album_id == $effectiveAlbumID);
                });

                foreach ($anonymousPermissions as $anonymousPermission)
                {
                    $permissionsCache[] = [
                        'album_id' => $album->id,
                        'permission_id' => $anonymousPermission->permission_id,
                        'created_at' => new \DateTime(),
                        'updated_at' => new \DateTime()
                    ];
                }

                $userPermissions = array_filter($albumUserPermissions->toArray(), function ($item) use ($effectiveAlbumID)
                {
                    return ($item->album_id == $effectiveAlbumID);
                });

                foreach ($userPermissions as $userPermission)
                {
                    $permissionsCache[] = [
                        'user_id' => $userPermission->user_id,
                        'album_id' => $album->id,
                        'permission_id' => $userPermission->permission_id,
                        'created_at' => new \DateTime(),
                        'updated_at' => new \DateTime()
                    ];
                }

                $groupPermissions = array_filter($albumGroupPermissions->toArray(), function ($item) use ($effectiveAlbumID)
                {
                    return ($item->album_id == $effectiveAlbumID);
                });

                foreach ($groupPermissions as $groupPermission)
                {
                    // Get a list of users in this group, and add one per user
                    $usersInGroup = array_filter($userGroups->toArray(), function ($item) use ($groupPermission)
                    {
                        return $item->group_id = $groupPermission->group_id;
                    });

                    foreach ($usersInGroup as $userGroup)
                    {
                        $permissionsCache[] = [
                            'user_id' => $userGroup->user_id,
                            'album_id' => $album->id,
                            'permission_id' => $groupPermission->permission_id,
                            'created_at' => new \DateTime(),
                            'updated_at' => new \DateTime()
                        ];
                    }
                }
            }
        }

        $this->savePermissionsCache($permissionsCache);
    }

    private function savePermissionsCache(array $cacheToSave)
    {
        DB::transaction(function() use ($cacheToSave)
        {
            DB::table('album_permissions_cache')->truncate();

            foreach ($cacheToSave as $cacheItem)
            {
                DB::table('album_permissions_cache')->insert($cacheItem);
            }
        });
    }
}