<?php

namespace App\Jobs;

use App\Model\Dialer;
use App\Model\Client\wallet;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class OutboundAICallJob implements ShouldQueue
{
    use InteractsWithQueue, Queueable, SerializesModels;

    // Issue #7: Prevent workers from stalling
    public $tries = 1;
    public $timeout = 120;

    protected $requestData;

    public function __construct(array $requestData)
    {
        $this->requestData = $requestData;
    }

    public function handle()
    {
        Log::info('Outbound AI Job Started', $this->requestData);

        $clientId   = $this->requestData['clientId'] ?? null;
        $campaignId = $this->requestData['campaign_id'] ?? null;
        $leadId     = $this->requestData['lead_id'] ?? null;

        if (!isAIQuotaAvailable()) {
            Log::warning('AI quota exhausted during job execution', [
                'campaign_id' => $campaignId,
                'client_id'   => $clientId,
            ]);

            // Mark FAILED so retry logic can re-queue later
            $this->updateLeadStatus($clientId, $campaignId, $leadId, 'FAILED');
            return;
        }

        // Wallet balance gate: skip call if wallet is depleted since cron dispatched this job
        if ($clientId && !wallet::hasBalance($clientId)) {
            Log::warning('Outbound call skipped due to insufficient wallet balance', [
                'client_id'   => $clientId,
                'campaign_id' => $campaignId,
                'lead_id'     => $leadId,
            ]);

            $this->updateLeadStatus($clientId, $campaignId, $leadId, 'SKIPPED_LOW_BALANCE');
            return;
        }

        // Campaign status gate: skip call if campaign was stopped/paused after job was queued
        if ($clientId && $campaignId) {
            $campaign = DB::connection('mysql_' . $clientId)
                ->selectOne("SELECT status, is_deleted FROM campaign WHERE id = :id", ['id' => $campaignId]);

            if (!$campaign || $campaign->status != 1 || $campaign->is_deleted == 1) {
                Log::warning('Outbound call skipped - campaign inactive or deleted', [
                    'client_id'   => $clientId,
                    'campaign_id' => $campaignId,
                    'lead_id'     => $leadId,
                    'status'      => $campaign->status ?? 'not_found',
                ]);

                $this->updateLeadStatus($clientId, $campaignId, $leadId, 'SKIPPED_CAMPAIGN_INACTIVE');
                return;
            }
        }

        try {
            // Transition to CALLED before dialing
            $this->updateLeadStatus($clientId, $campaignId, $leadId, 'CALLED');

            $dialer = new Dialer();
            $dialer->outboundAIDialAsterisk($this->requestData);

            // Dial succeeded — mark COMPLETED
            $this->updateLeadStatus($clientId, $campaignId, $leadId, 'COMPLETED');
        } catch (\Exception $e) {
            Log::error('Outbound AI Job dial failed', [
                'campaign_id' => $campaignId,
                'client_id'   => $clientId,
                'lead_id'     => $leadId,
                'error'       => $e->getMessage(),
            ]);

            $this->updateLeadStatus($clientId, $campaignId, $leadId, 'FAILED');
        }
    }

    public function failed(\Throwable $exception)
    {
        $clientId   = $this->requestData['clientId'] ?? null;
        $campaignId = $this->requestData['campaign_id'] ?? null;
        $leadId     = $this->requestData['lead_id'] ?? null;

        Log::error('Outbound AI Job failed permanently', [
            'campaign_id' => $campaignId,
            'client_id'   => $clientId,
            'lead_id'     => $leadId,
            'error'       => $exception->getMessage(),
        ]);

        $this->updateLeadStatus($clientId, $campaignId, $leadId, 'FAILED');
    }

    /**
     * Update lead_report status for the given lead.
     */
    private function updateLeadStatus($clientId, $campaignId, $leadId, string $status): void
    {
        if (!$clientId || !$campaignId || !$leadId) {
            return;
        }

        try {
            DB::connection('mysql_' . $clientId)->update(
                "UPDATE lead_report SET status = :status WHERE campaign_id = :campaign_id AND lead_id = :lead_id",
                [
                    'status'      => $status,
                    'campaign_id' => $campaignId,
                    'lead_id'     => $leadId,
                ]
            );
        } catch (\Exception $e) {
            Log::error('Failed to update lead_report status', [
                'campaign_id' => $campaignId,
                'lead_id'     => $leadId,
                'status'      => $status,
                'error'       => $e->getMessage(),
            ]);
        }
    }
}
