<?php

namespace App\Services;

use App\Enum\Automation\SystemDefaultOperatorEnum;
use App\Enum\ResourceEnum\ReviewStatusEnum;
use App\Enum\ResourceEnum\WorkFlowActivityStatusEnum;
use App\Enum\ResourceEnum\SmartApprovalReviewStatusEnum;
use App\Models\Automation\SmartApprovalProcessFlow;
use App\Models\Department;
use App\Models\Position;
use App\Models\SmartApprovalActivity;
use App\Models\User;
use App\Traits\ModelFinder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Schema;
use Spatie\Permission\Models\Role;

class ProcessFlowManager
{
    use ModelFinder;
    protected SmartApprovalActivity $approvalActivity;


    /**
     * Create a new class instance.
     */
    public function __construct(SmartApprovalActivity $approvalActivity)
    {
        $this->approvalActivity = $approvalActivity;
    }



    public function moveToNextStage(Model $service, $reviewRequest): Model
    {
        $service_type = get_class($service);
        $user = tenant_user();
        $activity = $this->approvalActivity
            ->where('service_type', '=', $service_type)
            ->where('service_id', '=', $service->id)
            ->where('status', '=', WorkFlowActivityStatusEnum::PENDING->value)
            ->latest('process_flow_id')
            ->firstOrFail();


        $currentFlow = $activity->flowLevel;
        if (!$this->isUserParticipant($currentFlow, $user)) {
            throw new \Exception("{$user->full_name} is not a participant in the current level.");
        }


        if ($reviewRequest['status'] == SmartApprovalReviewStatusEnum::APPROVED->value) {
            $nextLevel = $this->getNextLevel($currentFlow);

            // Update the current activity to mark it as completed

            $service_status = ReviewStatusEnum::PENDING_REVIEW->value;
            $activity_status = WorkFlowActivityStatusEnum::APPROVED->value;
            $activity->update(['status' => $activity_status]);

            // Insert Reviewer Comment
            $activity->approvalFlowReview()->create([
                'reviewer_id' => $user->id,
                'status' => $reviewRequest['status'] ?? null,
                'comment' => $reviewRequest['comment'] ?? null,
            ]);


            if ($nextLevel) {
                // Create a new activity for the next flow level
                $this->approvalActivity->create([
                    'smart_approval_id' => $activity->smart_approval_id,
                    'process_flow_id' => $nextLevel->id,
                    'service_type' => get_class($service),
                    'service_id' => $service->id,
                    'status' => WorkFlowActivityStatusEnum::PENDING->value,
                ]);
            } else {
                // The whole workflow is completed
                $service_status = ReviewStatusEnum::COMPLETED->value;
            }

        } else {
            $service_status = ReviewStatusEnum::DECLINED->value;
            // Insert Reviewer Comment
            $activity->approvalFlowReview()->create([
                'reviewer_id' => $user->id,
                'status' => $reviewRequest['status'] ?? null,
                'comment' => $reviewRequest['comment'] ?? null,
            ]);
        }


        if (Schema::hasColumn($service->getTable(),'status'))
            $service->update(['status' => $service_status]);

        return $activity;
    }




    protected function isUserParticipant(SmartApprovalProcessFlow $flowLevel, $user): ?bool
    {
        $participant = $flowLevel->participant;

        if ($participant instanceof Department) {
            return $user->department?->where('id','=',$participant->id)->exists();
            // return $user->department_id == $participant->id;
        } elseif ($participant instanceof Position) {
            return $user->position?->where('id','=',$participant->id)->exists();
            //  return $user->position_id == $participant->id;
        } elseif ($participant instanceof User) {
            return $user->id == $participant->id;
        }
        elseif ($participant instanceof Role) {
            $role = Role::findById($participant->id);
            return $user->hasRole($role);
        }

        return false;
    }

    public function getNextLevel(SmartApprovalProcessFlow $currentFlowLevel)
    {
        return $currentFlowLevel->approvalProcess->approvalProcessFlow()
            ->where('level', '>', $currentFlowLevel->level)
            ->orderBy('level')->first();
    }


    public function triggerServiceProcessFlow(SmartApprovalActivity $approvalActivity): bool
    {
        $meets_all_Criteria = true;
        $activity = $approvalActivity;
        $criteria = $approvalActivity->smartApproval?->criteriaFlow;


        // Check if it meets criteria
        foreach ($criteria as $criterion)
        {
            $logical_operator = $criterion->logical_operator;
            // Evaluate the criterion
            $meets_criterion = $this->evaluateCriterion($criterion);

            // If logical operator is AND and service doesn't meet the criterion, immediately break loop
            if ($logical_operator == 'AND' && !$meets_criterion) {
                $meets_all_Criteria = false;
                break;
            }

            // If logical operator is OR and service meets the criterion, set meets_all_criteria to true
            if ($logical_operator == 'OR' && $meets_criterion) {
                $meets_all_Criteria = true;
                break;
            }

            // If logical operator is OR and service doesn't meet the criterion, continue evaluating
            if ($logical_operator == 'OR' && !$meets_criterion) {
                $meets_all_Criteria = false;
                continue;
            }

            // If logical operator is AND and service meets the criterion, continue evaluating
//            if ($logical_operator == 'AND' && $meets_criterion) {
//                continue;
//            }
        }

        return $meets_all_Criteria;
    }


    protected function evaluateCriterion($criterion): bool
    {
        $model = $this->getModelFromEnum($criterion->left_operand);
        $right_operand = is_array($criterion->right_operand) ? $criterion->right_operand : json_decode($criterion->right_operand, true);

        switch ($criterion->operator){
            case SystemDefaultOperatorEnum::CONTAINS->value:
                $boolean =  $model->whereIn('id',$right_operand ?? [])->exists();
                break;

            case SystemDefaultOperatorEnum::NOT_CONTAINS->value:
                $boolean =  $model->whereNotIn('id',$right_operand ?? [])->exists();
                break;

            case SystemDefaultOperatorEnum::IS_EMPTY->value:
                $boolean =  $model->count() == 0;
                break;

            case SystemDefaultOperatorEnum::IS_NOT_EMPTY->value:
                $boolean =  $model->count() > 0;
                break;

            default:
                $boolean =  false;
        }

        return $boolean;
    }

}
