<?php

namespace App\Services;

use App\Models\Comment;
use App\Models\File;
use App\Models\Meeting;
use App\Models\Project;
use App\Models\Sprint;
use App\Models\Task;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;

class ResourceAccessService
{
    public function canSeeAll(User $user): bool
    {
        $user->loadMissing('roles.permissions');

        return $user->roles->contains('name', 'admin');
    }

    public function projects(User $user): Builder
    {
        $query = Project::query();
        if ($this->canSeeAll($user)) {
            return $query;
        }

        return $query->where(function (Builder $scope) use ($user) {
            $scope->where('project_manager_id', $user->id)
                ->orWhere('created_by', $user->id)
                ->orWhereHas('members', fn (Builder $members) => $members->where('users.id', $user->id));
        });
    }

    public function tasks(User $user): Builder
    {
        $query = Task::query();
        if ($this->canSeeAll($user)) {
            return $query;
        }

        return $query->where(function (Builder $scope) use ($user) {
            $scope->where('assignee_id', $user->id)
                ->orWhere('reporter_id', $user->id)
                ->orWhere('created_by', $user->id)
                ->orWhereIn('project_id', $this->projects($user)->select('projects.id'));
        });
    }

    public function sprints(User $user): Builder
    {
        $query = Sprint::query();
        if ($this->canSeeAll($user)) {
            return $query;
        }

        return $query->where(function (Builder $scope) use ($user) {
            $scope->where('created_by', $user->id)
                ->orWhereHas('members', fn (Builder $members) => $members->where('users.id', $user->id))
                ->orWhereIn('project_id', $this->projects($user)->select('projects.id'));
        });
    }

    public function meetings(User $user): Builder
    {
        $query = Meeting::query();
        if ($this->canSeeAll($user)) {
            return $query;
        }

        return $query->where(function (Builder $scope) use ($user) {
            $scope->where('created_by', $user->id)
                ->orWhere('owner_id', $user->id)
                ->orWhere('facilitator_id', $user->id)
                ->orWhereHas('participants', fn (Builder $participants) => $participants->where('users.id', $user->id))
                ->orWhereIn('project_id', $this->projects($user)->select('projects.id'));
        });
    }

    public function comments(User $user): Builder
    {
        $query = Comment::query();
        if ($this->canSeeAll($user)) {
            return $query;
        }

        return $query->where(function (Builder $scope) use ($user) {
            $scope->where('user_id', $user->id)
                ->orWhere(function (Builder $tasks) use ($user) {
                    $tasks->where('commentable_type', Task::class)
                        ->whereIn('commentable_id', $this->tasks($user)->select('tasks.id'));
                })
                ->orWhere(function (Builder $projects) use ($user) {
                    $projects->where('commentable_type', Project::class)
                        ->whereIn('commentable_id', $this->projects($user)->select('projects.id'));
                })
                ->orWhere(function (Builder $meetings) use ($user) {
                    $meetings->where('commentable_type', Meeting::class)
                        ->whereIn('commentable_id', $this->meetings($user)->select('meetings.id'));
                });
        });
    }

    public function files(User $user): Builder
    {
        $query = File::query();
        if ($this->canSeeAll($user)) {
            return $query;
        }

        return $query->where(function (Builder $scope) use ($user) {
            $scope->where('user_id', $user->id)
                ->orWhere(function (Builder $projects) use ($user) {
                    $projects->where('fileable_type', Project::class)
                        ->whereIn('fileable_id', $this->projects($user)->select('projects.id'));
                })
                ->orWhere(function (Builder $tasks) use ($user) {
                    $tasks->where('fileable_type', Task::class)
                        ->whereIn('fileable_id', $this->tasks($user)->select('tasks.id'));
                })
                ->orWhere(function (Builder $meetings) use ($user) {
                    $meetings->where('fileable_type', Meeting::class)
                        ->whereIn('fileable_id', $this->meetings($user)->select('meetings.id'));
                })
                ->orWhere(function (Builder $comments) use ($user) {
                    $comments->where('fileable_type', Comment::class)
                        ->whereIn('fileable_id', $this->comments($user)->select('comments.id'));
                });
        });
    }

    public function canAccessProject(User $user, Project $project): bool
    {
        return $this->projects($user)->whereKey($project->getKey())->exists();
    }

    public function canAccessTask(User $user, Task $task): bool
    {
        return $this->tasks($user)->whereKey($task->getKey())->exists();
    }

    public function canAccessSprint(User $user, Sprint $sprint): bool
    {
        return $this->sprints($user)->whereKey($sprint->getKey())->exists();
    }

    public function canAccessMeeting(User $user, Meeting $meeting): bool
    {
        return $this->meetings($user)->whereKey($meeting->getKey())->exists();
    }

    public function canAccessComment(User $user, Comment $comment): bool
    {
        return $this->comments($user)->whereKey($comment->getKey())->exists();
    }

    public function canAccessFile(User $user, File $file): bool
    {
        return $this->files($user)->whereKey($file->getKey())->exists();
    }
}
