<?php

namespace App\Http\Controllers\Twilio;

use App\Enum\Communication\CommunicationStatus;
use App\Models\Communication\Call;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use Twilio\TwiML\VoiceResponse;

/**
 * Handles the action callback Twilio POSTs when a <Dial> verb completes.
 *
 * If the dial succeeded (DialCallStatus = completed) we end the parent
 * call cleanly. For any other outcome — no-answer, busy, failed, or
 * canceled (which includes the SDK reject() path for agent decline) —
 * we mark the inbound Communication as Missed (so it appears in the
 * Missed Calls panel) and fall through to a voicemail prompt. If the
 * caller leaves a message the recording callback will upgrade the
 * status from Missed → Voicemail.
 */
class TwilioDialFallbackController {
    public function __invoke(Request $request): Response {
        $dialCallStatus = $request->input('DialCallStatus');
        $callSid        = $request->input('CallSid');

        Log::debug('TwilioDialFallbackController: dial action', [
            'CallSid'          => $callSid,
            'DialCallSid'      => $request->input('DialCallSid'),
            'DialCallStatus'   => $dialCallStatus,
            'DialCallDuration' => $request->input('DialCallDuration'),
        ]);

        $voice = new VoiceResponse();

        if ($dialCallStatus === 'completed') {
            // Agent answered and the conversation ended normally. Just hang up
            // the parent leg; the recording callback for the connected call
            // will already be on its way.
            $voice->hangup();

            return response((string) $voice, 200)->header('Content-Type', 'text/xml');
        }

        // No agent answered. Mark as Missed before offering voicemail so the
        // dashboard's Missed Calls panel picks it up immediately. The
        // recording callback will upgrade to Voicemail if a message is left.
        $this->markCommunicationMissed($callSid);

        $voice->say('Please leave a message after the tone.');
        $voice->record([
            'maxLength'                     => 120,
            'playBeep'                      => true,
            'recordingStatusCallback'       => route('twilio.voice.recording'),
            'recordingStatusCallbackMethod' => 'POST',
            'recordingStatusCallbackEvent'  => 'completed',
        ]);

        return response((string) $voice, 200)->header('Content-Type', 'text/xml');
    }

    protected function markCommunicationMissed(?string $callSid): void
    {
        if (! $callSid) {
            return;
        }

        $call = Call::with('communication')
            ->where('provider_call_sid', $callSid)
            ->first();

        if (! $call || ! $call->communication) {
            return;
        }

        $communication = $call->communication;

        // Guard against overwriting any later/terminal status that might have
        // already been set (e.g. Voicemail by a racing recording callback).
        if (! in_array($communication->status, [
            CommunicationStatus::Initiated->value,
            CommunicationStatus::Ringing->value,
        ], true)) {
            return;
        }

        $communication->update([
            'status'   => CommunicationStatus::Missed->value,
            'ended_at' => $communication->ended_at ?? now(),
        ]);
    }
}
