<?php

namespace Modules\PMCore\App\Policies;

use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Database\Eloquent\Model;
use Modules\PMCore\App\Models\Project;

/**
 * Policy for project tasks from TaskSystem module.
 *
 * This policy handles authorization for tasks linked to projects
 * via the polymorphic taskable relationship in TaskSystem.
 */
class ProjectTaskPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can view any tasks.
     */
    public function viewAny(User $user, Project $project): bool
    {
        // Can view tasks if can view the project
        return $user->can('pmcore.view-project-tasks') &&
               app(ProjectPolicy::class)->view($user, $project);
    }

    /**
     * Determine whether the user can view the task.
     *
     * @param  Model  $task  TaskSystem Task model instance
     */
    public function view(User $user, Model $task): bool
    {
        if (! $user->can('pmcore.view-project-tasks')) {
            return false;
        }

        $project = $this->getProjectFromTask($task);

        return $project && app(ProjectPolicy::class)->view($user, $project);
    }

    /**
     * Determine whether the user can create tasks.
     */
    public function create(User $user, Project $project): bool
    {
        return $user->can('pmcore.create-project-task') &&
               app(ProjectPolicy::class)->view($user, $project);
    }

    /**
     * Determine whether the user can update the task.
     *
     * @param  Model  $task  TaskSystem Task model instance
     */
    public function update(User $user, Model $task): bool
    {
        $project = $this->getProjectFromTask($task);
        if (! $project) {
            return false;
        }

        if ($user->can('pmcore.edit-project-task')) {
            return app(ProjectPolicy::class)->view($user, $project);
        }

        if ($user->can('pmcore.edit-own-task')) {
            return $task->assigned_to === $user->id;
        }

        return false;
    }

    /**
     * Determine whether the user can delete the task.
     *
     * @param  Model  $task  TaskSystem Task model instance
     */
    public function delete(User $user, Model $task): bool
    {
        $project = $this->getProjectFromTask($task);

        return $project &&
               $user->can('pmcore.delete-project-task') &&
               app(ProjectPolicy::class)->view($user, $project);
    }

    /**
     * Determine whether the user can assign the task.
     *
     * @param  Model  $task  TaskSystem Task model instance
     */
    public function assign(User $user, Model $task): bool
    {
        $project = $this->getProjectFromTask($task);

        return $project &&
               $user->can('pmcore.assign-project-task') &&
               app(ProjectPolicy::class)->view($user, $project);
    }

    /**
     * Determine whether the user can complete the task.
     *
     * @param  Model  $task  TaskSystem Task model instance
     */
    public function complete(User $user, Model $task): bool
    {
        return $user->can('pmcore.complete-project-task') &&
               ($task->assigned_to === $user->id || $user->can('pmcore.edit-project-task'));
    }

    /**
     * Determine whether the user can start the task.
     *
     * @param  Model  $task  TaskSystem Task model instance
     */
    public function start(User $user, Model $task): bool
    {
        return $user->can('pmcore.start-project-task') &&
               ($task->assigned_to === $user->id || $user->can('pmcore.edit-project-task'));
    }

    /**
     * Determine whether the user can reorder tasks.
     */
    public function reorder(User $user, Project $project): bool
    {
        return $user->can('pmcore.reorder-project-tasks') &&
               app(ProjectPolicy::class)->view($user, $project);
    }

    /**
     * Get the project associated with a task via polymorphic relationship.
     *
     * TaskSystem uses taskable_type and taskable_id for polymorphic relationships.
     */
    private function getProjectFromTask(Model $task): ?Project
    {
        // TaskSystem uses taskable relationship (taskable_type, taskable_id)
        if (method_exists($task, 'taskable') && $task->taskable instanceof Project) {
            return $task->taskable;
        }

        // Fallback: check if taskable_id matches a project
        if (isset($task->taskable_id) && isset($task->taskable_type)) {
            if ($task->taskable_type === Project::class || str_contains($task->taskable_type, 'Project')) {
                return Project::find($task->taskable_id);
            }
        }

        return null;
    }
}
