<?php

namespace App\Services;

use App\Models\{ ItemRequest, ApprovalInstance, ApprovalAction, ApprovalStepTemplate, User };
use Illuminate\Support\Facades\DB;
use Illuminate\Auth\Access\AuthorizationException;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;


class ApprovalEngine
{
    public function submit(ItemRequest $req, User $requester): void
    {
        $expectedId = (int) $req->requester_id;
        $actualId   = (int) $requester->id;
        
        if ($actualId !== $expectedId && !$requester->isAdmin()) {
            throw new AuthorizationException("Only the requester can submit.");
        }

        DB::transaction(function () use ($req, $requester) {
            $instance = $req->instance;
            if (!$instance) {
                $instance = ApprovalInstance::create([
                    'item_request_id' => $req->id,
                    'flow_template_id'=> $req->flow_template_id,
                    'status'          => 'InProgress',
                    'started_at'      => Carbon::now(),
                ]);
            } else {
                $instance->update([
                    'status'          => 'InProgress',
                    'started_at'      => Carbon::now(),
                    'ended_at'    => null,
                ]);
            }

            $req->update([
                'status'          => 'InReview',
                'current_step_no' => 1,
            ]);

            ApprovalAction::create([
                'approval_instance_id' => $instance->id,
                'step_no'       => 1,
                'actor_user_id' => $requester->id,
                'action'        => 'Submit',
                'comment'       => null,
                'acted_at'      => Carbon::now(),
            ]);
        });
    }

    public function act(ItemRequest $req, int $actorId, string $action, ?string $comment = null): void
    {
        $actor = User::findOrFail($actorId);
        $instance = $req->instance()->firstOrFail();

        if ($instance->status !== 'InProgress' || $req->status !== 'InReview') {
            throw new \RuntimeException("This request is not actionable.");
        }

        if (!$this->isActorCurrentApprover($req, $actor)) {
            throw new AuthorizationException("You are not an approver for the current step.");
        }

        DB::transaction(function () use ($req, $instance, $actor, $action, $comment) {
            $currentStep = $req->current_step_no;
            $maxStep = (int) ApprovalStepTemplate::where('flow_template_id', $req->flow_template_id)->max('step_no');

            ApprovalAction::create([
                'approval_instance_id' => $instance->id,
                'step_no'       => $currentStep,
                'actor_user_id' => $actor->id,
                'action'        => $action,
                'comment'       => $comment,
                'acted_at'      => now(),
            ]);

            if ($action === 'Approve') {
                if ($currentStep < $maxStep) {
                    $req->update(['current_step_no' => $currentStep + 1]);
                } else {
                    $instance->update(['status' => 'Approved', 'ended_at' => now()]);
                    $req->update(['status' => 'Approved']);
                }
            } elseif ($action === 'Reject') {
                $instance->update(['status' => 'Rejected', 'ended_at' => now()]);
                $req->update(['status' => 'Rejected']);
            } else {
                throw new \InvalidArgumentException('Invalid action.');
            }
        });
    }

    protected function isActorCurrentApprover(ItemRequest $req, User $actor): bool
    {
        if ($actor->isAdmin()) return true;
    
        $step = ApprovalStepTemplate::where('flow_template_id', $req->flow_template_id)
                ->where('step_no', $req->current_step_no)->first();
    
        if (!$step) return false;
    
        // check new approver records
        $exists = \App\Models\ApprovalStepApprover::where('step_template_id', $step->id)
            ->where(function($q) use ($actor) {
                $q->where('approver_user_id', $actor->id)
                  ->orWhere('approver_role_id', $actor->role_id);
            })->exists();
    
        if ($exists) return true;
    
        // fallback to legacy single columns (if you still have them)
        if ($step->approver_user_id && $step->approver_user_id === $actor->id) return true;
        if ($step->approver_role_id && $step->approver_role_id === $actor->role_id) return true;
    
        return false;
    }
    
    public function isLastApprover(ItemRequest $req, User $actor): bool
    {
        $lastApprove = optional($req->instance)->actions
        ->where('action', 'Approve')
        ->sortByDesc('acted_at')
        ->first();

        return $lastApprove && $lastApprove->actor?->id === $actor->id;
    }

}
