<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\BaseController;
use App\Core\Database;
use App\Core\Request;
use App\Core\Response;
use App\Helpers\AjaxResponse;
use App\Models\IntegrationModel;
use App\Services\VoiceAgentService;
use App\Services\TwilioClient;

final class VoiceAgentController extends BaseController
{
    // ---- Public Twilio webhooks (signature-verified, not session-auth'd) ----

    public function incomingCall(Request $request): Response
    {
        if (!$this->verifyTwilioSignature($request)) {
            return Response::html('Forbidden', 403);
        }

        $callSid = (string) $request->input('CallSid');
        $from = (string) $request->input('From');
        $businessLineId = $this->resolveBusinessLineFromNumber((string) $request->input('To'));

        $twiml = (new VoiceAgentService())->handleIncomingCall($callSid, $from, $businessLineId, base_url('voice/gather'));

        return $this->twimlResponse($twiml);
    }

    public function gatherResult(Request $request): Response
    {
        if (!$this->verifyTwilioSignature($request)) {
            return Response::html('Forbidden', 403);
        }

        $conversationId = (int) $request->query('conversation_id');
        $speechResult = (string) $request->input('SpeechResult', '');
        $businessLineId = $this->resolveBusinessLineFromNumber((string) $request->input('To'));

        $twiml = (new VoiceAgentService())->handleSpeechInput($conversationId, $speechResult, $businessLineId, base_url('voice/gather'));

        return $this->twimlResponse($twiml);
    }

    public function statusCallback(Request $request): Response
    {
        if (!$this->verifyTwilioSignature($request)) {
            return Response::html('Forbidden', 403);
        }

        $callSid = (string) $request->input('CallSid');
        $status = (string) $request->input('CallStatus');
        $recordingUrl = $request->input('RecordingUrl');
        $duration = $request->input('CallDuration') !== null ? (int) $request->input('CallDuration') : null;

        (new VoiceAgentService())->recordCallEnd($callSid, $status, is_string($recordingUrl) ? $recordingUrl : null, $duration);

        return Response::html('', 204);
    }

    // ---- Admin ----

    public function index(Request $request): Response
    {
        $stmt = Database::connection()->prepare(
            "SELECT c.*, bl.name AS business_line_name, CONCAT(l.first_name,' ',COALESCE(l.last_name,'')) AS lead_name
             FROM conversations c
             LEFT JOIN business_lines bl ON bl.id = c.business_line_id
             LEFT JOIN leads l ON l.id = c.related_lead_id
             WHERE c.channel = 'voice_agent'
             ORDER BY c.started_at DESC LIMIT 50"
        );
        $stmt->execute();

        return $this->view('ai/voice-agent', [
            'title' => 'AI Voice Agent',
            'activeNav' => 'voice-agent',
            'breadcrumbs' => [['Home', 'dashboard'], ['AI', 'ai-assistant'], ['AI Voice Agent', 'voice-agent']],
            'calls' => $stmt->fetchAll(),
            'twilioConfigured' => (new TwilioClient())->isConfigured(),
        ]);
    }

    public function initiateCall(Request $request): Response
    {
        $data = $this->validateOrFail($request, [
            'to_number' => 'required|string|max:20',
            'business_line_id' => 'required|integer|exists:business_lines,id',
            'lead_id' => 'nullable|integer|exists:leads,id',
        ]);

        $result = (new VoiceAgentService())->initiateOutboundCall(
            $data['to_number'],
            (int) $data['business_line_id'],
            $data['lead_id'] ?? null,
            base_url('voice/incoming')
        );

        return $result['success'] ? AjaxResponse::success($result, 'Call initiated.') : AjaxResponse::error($result['error'], 422);
    }

    private function twimlResponse(string $xml): Response
    {
        return Response::html($xml)->withHeader('Content-Type', 'text/xml');
    }

    private function verifyTwilioSignature(Request $request): bool
    {
        $creds = (new IntegrationModel())->credentialsFor('twilio');
        if ($creds === null || empty($creds['auth_token'])) {
            return false;
        }

        $signature = $request->header('X-Twilio-Signature');
        if (!is_string($signature)) {
            return false;
        }

        $url = base_url(ltrim($request->path(), '/'));
        if ($request->query('conversation_id') !== null) {
            $url .= '?conversation_id=' . $request->query('conversation_id');
        }

        return (new TwilioClient())->verifyWebhookSignature($url, $request->bodyOnly(), $signature, $creds['auth_token']);
    }

    private function resolveBusinessLineFromNumber(string $toNumber): int
    {
        $stmt = Database::connection()->query('SELECT id FROM business_lines ORDER BY id LIMIT 1');

        return (int) $stmt->fetchColumn();
    }
}
