<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Tenant;
use App\Models\Agent;
use App\Models\Queue;
use App\Models\WaitingList;
use App\Models\DailyMetric;
use Carbon\Carbon;
use App\Events\DashboardUpdate;

class AmiEventController extends Controller
{
    public function handle(Request $request)
    {
        $token = $request->header('X-Tenant-Token');
        $tenant = Tenant::where('api_key', $token)->first();

        if (!$tenant) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        $data = $request->all();
        $eventName = $data['Event'] ?? null;
        $queueNumber = $data['Queue'] ?? null;

        // Tenta achar a interface. Se for MemberStatus, vem em 'Interface'. Se for AgentConnect, vem em 'Interface' ou 'MemberName'
        $interface = $data['Interface'] ?? $data['MemberName'] ?? null;

        // Auto-discovery de Filas e Agentes
        if ($queueNumber) {
            $this->saveQueues($queueNumber, $tenant);
        }
        if ($interface) {
            $this->saveAgent($interface, $tenant);
        }

        if (!$eventName || !$queueNumber) {
            return response()->json(['status' => 'ignored']);
        }

        // Recupera Fila
        $queue = Queue::where('tenant_id', $tenant->id)
            ->where('source_id', $queueNumber)
            ->first();

        if (!$queue) {
            return response()->json(['error' => 'Fila não encontrada'], 404);
        }

        $agent = $this->findAgent($tenant->id, $data);


        switch ($eventName) {
            case 'QueueCallerJoin':
                $this->handleJoin($queue, $data);
                break;

            case 'AgentConnect':
                // Foco: Mudar para 'talking' e atualizar métricas
                $this->handleConnect($queue, $data);
                break;

            case 'AgentComplete':
                // Foco: Encerrar contagem de tempo de fala
                $this->handleComplete($queue, $data);
                break;

            case 'QueueCallerAbandon':
                $this->handleAbandon($queue, $data);
                break;

            case 'QueueMemberPause':
                // Evento explícito de pausa (Alguém clicou no botão de pausa)
                if ($agent) $this->handlePause($agent, $data, $tenant->id);
                break;

            case 'AgentRingNoAnswer':
                if ($agent) $this->handleRingNoAnswer($agent, $tenant->id);
                break;

            case 'QueueMemberStatus':
                // Foco: Atualizar Presença (Offline, Disponível, Pausado, Busy)
                if ($agent) $this->handleMemberStatus($agent, $data, $tenant->id);
                break;
        }

        return response()->json(['status' => 'success']);
    }

    // =========================================================================
    // HANDLERS
    // =========================================================================

    private function handleMemberStatus($agent, $data, $tenantId)
    {
        $isPaused = ($data['Paused'] ?? '0') == '1';
        $asteriskStatus = $data['Status'] ?? null;

        $targetStatus = 'offline';
        $targetReason = null;

        if ($isPaused) {
            $targetStatus = 'paused';
            $targetReason = !empty($data['PausedReason']) ? $data['PausedReason'] : ($agent->pause_reason ?? 'Pausa');
        } else {
            $targetReason = null;
            switch ($asteriskStatus) {
                case '1':
                    $targetStatus = 'available';
                    break;
                case '2':
                case '3':
                case '6':
                    $targetStatus = 'talking';
                    break;
                case '5':
                    $targetStatus = 'offline';
                    break;
                default:
                    $targetStatus = 'offline';
                    break;
            }
        }

        // TRAVA DE IDEMPOTÊNCIA (Igual ao handlePause)
        if ($agent->status === $targetStatus && $agent->pause_reason === $targetReason) {
            return;
        }

        $agent->status = $targetStatus;
        $agent->pause_reason = $targetReason;
        $agent->last_status_change = now();
        $agent->save();

        broadcast(new DashboardUpdate($tenantId));
    }

    private function handleConnect($queue, $data)
    {
        // 1. Remove da Lista de Espera
        WaitingList::where('queue_id', $queue->id)
            ->where('caller_number', $data['CallerIDNum'])
            ->delete();

        // 2. Atualiza Métricas da Fila
        $metric = $this->getTodayMetric($queue);
        $holdTime = intval($data['HoldTime'] ?? 0);
        $newAvg = (($metric->avg_wait_time * $metric->answered_count) + $holdTime) / ($metric->answered_count + 1);

        $metric->avg_wait_time = $newAvg;
        $metric->answered_count += 1;
        $metric->save();

        // 3. Atualiza Agente para Talking (Feedback Visual Imediato)
        $agent = $this->findAgent($queue->tenant_id, $data);
        if ($agent) {
            $agent->status = 'talking';
            $agent->last_status_change = now();
            $agent->increment('total_calls_answered');
            $agent->save();
        }

        $this->broadcastUpdate($queue);
    }

    private function handleComplete($queue, $data)
    {
        // Atualiza tempo médio falado
        $talkTime = intval($data['TalkTime'] ?? 0);
        $metric = $this->getTodayMetric($queue);

        if ($metric->answered_count > 0) {
            $newAvg = (($metric->avg_talk_time * ($metric->answered_count - 1)) + $talkTime) / $metric->answered_count;
            $metric->avg_talk_time = $newAvg;
            $metric->save();
        }

        // NOTA: Removemos a lógica de mudar status para 'available' aqui.
        // Deixamos o 'QueueMemberStatus' cuidar disso quando o telefone for colocado no gancho.
        // Isso evita conflitos se o agente desligar e imediatamente receber outra chamada.

        $this->broadcastUpdate($queue);
    }

    private function handlePause($agent, $data, $tenantId)
    {
        $isPaused = isset($data['Paused']) && $data['Paused'] == '1';
        $targetStatus = $isPaused ? 'paused' : 'available'; // Se despausar, assume livre

        $targetReason = null;
        if ($isPaused) {
            $targetReason = $data['Reason'] ?? $data['PausedReason'] ?? 'Pausa';
            if (trim($targetReason) === '') $targetReason = 'Pausa';
        }

        // --- TRAVA DE IDEMPOTÊNCIA ---
        // Se o agente está em 10 filas, esse evento dispara 10 vezes.
        // Se o status já for igual, IGNORA para não spamar o WebSocket.
        if ($agent->status === $targetStatus && $agent->pause_reason === $targetReason) {
            return;
        }

        $agent->status = $targetStatus;
        $agent->pause_reason = $targetReason;
        $agent->last_status_change = now();
        $agent->save();

        broadcast(new DashboardUpdate($tenantId));
    }

    private function handleAbandon($queue, $data)
    {
        WaitingList::where('queue_id', $queue->id)
            ->where('caller_number', $data['CallerIDNum'])
            ->delete();

        $this->updateMetric($queue, 'abandoned_count', 1);
        $this->broadcastUpdate($queue);
    }

    private function handleRingNoAnswer($agent, $tenantId)
    {
        $agent->increment('total_ring_no_answer');
        broadcast(new DashboardUpdate($tenantId));
    }

    private function handleJoin($queue, $data)
    {
        WaitingList::create([
            'tenant_id' => $queue->tenant_id,
            'queue_id' => $queue->id,
            'caller_number' => $data['CallerIDNum'],
            'caller_name' => $data['CallerIDName'] ?? 'Desconhecido',
            'entered_at' => now(),
        ]);

        $this->updateMetric($queue, 'received_count', 1);
        $this->broadcastUpdate($queue);
    }

    // =========================================================================
    // AUXILIARES
    // =========================================================================

    private function saveAgent($interface, $tenant)
    {

        $exists = Agent::where('tenant_id', $tenant->id)
            ->where('interface', $interface)
            ->exists();

        if (!$exists) {
            // Lógica de extração de nome
            $name = $interface;
            if (strpos($interface, '/') !== false) {
                $parts = explode('/', $interface);
                $name = end($parts);
            }

            Agent::create([
                'tenant_id' => $tenant->id,
                'name' => "Agente $name",
                'interface' => $interface,
                'status' => 'available'
            ]);
        }
    }

    private function saveQueues($queueSourceId, $tenant)
    {
        $exists = Queue::where('tenant_id', $tenant->id)
            ->where('source_id', $queueSourceId)
            ->exists();

        if (!$exists) {
            Queue::create([
                'tenant_id' => $tenant->id,
                'type' => 'voice',
                'source_id' => $queueSourceId,
                'name' => "Fila $queueSourceId",
                'sector' => null
            ]);
        }
    }

    private function findAgent($tenantId, $data)
    {
        $interface = $data['Interface'] ?? $data['MemberName'] ?? null;


        return Agent::where('tenant_id', $tenantId)
            ->where('interface', $interface)
            ->first();
    }

    private function getTodayMetric($queue)
    {
        return DailyMetric::firstOrCreate(
            [
                'queue_id' => $queue->id,
                'date' => Carbon::today()
            ],
            [
                'tenant_id' => $queue->tenant_id,
                'received_count' => 0,
                'answered_count' => 0,
                'abandoned_count' => 0
            ]
        );
    }

    private function updateMetric($queue, $field, $value)
    {
        $metric = $this->getTodayMetric($queue);
        $metric->increment($field, $value);
    }

    private function broadcastUpdate($queueOrTenantId)
    {
        $tenantId = is_object($queueOrTenantId) ? $queueOrTenantId->tenant_id : $queueOrTenantId;
        broadcast(new DashboardUpdate($tenantId));
    }
}
