<?php

namespace App\Livewire\Agent;

use App\Models\Activity;
use App\Models\AgentLog;
use App\Models\Contact;
use App\Models\Event;
use App\Models\Note;
use App\Models\Task;
use App\Services\AgentActionService;
use App\Services\AgentAIService;
use App\Services\AgentContextService;
use Carbon\Carbon;
use Livewire\Component;

class Index extends Component
{
    public string $message = '';

    public $user;
    public $subscription;
    public $plan;

    public int $usage        = 0;
    public int $limit        = 0;
    public int $usagePercent = 0;

    public ?array $lastAction = null;

    public array $conversation = [];

    // Token-Tracking über die gesamte Konversation hinweg
    public int $conversationPromptTokens     = 0;
    public int $conversationCompletionTokens = 0;
    public int $conversationTotalTokens      = 0;
    public float $conversationCostUsd        = 0;

    protected $listeners = [
        'agent:result' => 'handleAgentResult',
    ];

    public function mount(): void
    {
        $this->user = auth()->user();

        $this->subscription = $this->user->subscription()->with('plan')->first()
            ?? $this->user->latestSubscription()->with('plan')->first();

        $this->plan  = $this->subscription?->plan;
        $this->limit = $this->user->effective_limit;

        $this->recalcUsage();
    }

    public function send(string $text = '', bool $withAudio = false): ?array
    {
        $userMessage = trim($text ?: $this->message);
        if (!$userMessage) return null;

        $this->reset('message');

        $hardLimit = (int) ceil($this->limit * 1.05);

        // Stufe 1: Hart blockieren ab 105%
        if ($this->limit > 0 && $this->usage >= $hardLimit) {
            $this->dispatch('notify', [
                'type'    => 'error',
                'title'   => 'Limit erreicht',
                'message' => 'Dein monatliches Kontingent ist aufgebraucht. Upgrade auf Pro oder warte bis zum nächsten Monat.',
            ]);
            return null;
        }

        // Stufe 2: Warnung bei 100%-105% — Anfrage läuft durch
        if ($this->limit > 0 && $this->usage >= $this->limit) {
            $this->dispatch('notify', [
                'type'    => 'warning',
                'title'   => 'Fast aufgebraucht',
                'message' => 'Du nutzt deine Toleranzreserve. Dein Kontingent ist bald erschöpft.',
            ]);
        }

        $startTime = microtime(true);

        $aiConfig = $this->plan?->ai_config ?? [];
        if (is_string($aiConfig)) {
            $aiConfig = json_decode($aiConfig, true);
        }

        $model = $aiConfig['model'] ?? 'gpt-4o-mini';

        $historyForAI = array_slice($this->conversation, -8);
        $messagesForAI = array_merge($historyForAI, [
            ['role' => 'user', 'content' => $userMessage],
        ]);

        // User-Kontext (geteilter Service → Web + API identisch)
        $userContext = app(AgentContextService::class)->build($this->user);
        \Log::info('UserContext Länge: ' . str_word_count($userContext) . ' Wörter, ' . strlen($userContext) . ' Zeichen');

        $parsed = AgentAIService::chat($messagesForAI, $aiConfig, $userContext);
        $usage  = $parsed['_usage'] ?? [];

        $this->conversationPromptTokens     += $usage['prompt_tokens'] ?? 0;
        $this->conversationCompletionTokens += $usage['completion_tokens'] ?? 0;
        $this->conversationTotalTokens      += $usage['total_tokens'] ?? 0;
        $this->conversationCostUsd          += $this->calculateCost($usage, $model);

        try {
            // ── Multi-Action: Array von Aktionen ──────────────────────────
            if (isset($parsed['_multi'])) {
                $actions = $parsed['_multi'];
                $results = [];
                $messages = [];

                foreach ($actions as $action) {
                    if (!isset($action['type'])) continue;
                    $result = AgentActionService::handle($this->user, $action);
                    $results[] = $result;

                    if ($result['status'] === 'success') {
                        $messages[] = $result['message'] ?? 'Erledigt';

                        if (in_array($action['type'], ['event', 'event_update'])) {
                            $this->dispatch('eventCreated');
                        }
                    }
                }

                $duration = round((microtime(true) - $startTime) * 1000);
                $credits = $this->calculateCredits(['type' => 'multi'], $duration, $usage);

                $combinedResult = [
                    'status' => 'success',
                    'message' => implode(' | ', $messages) ?: 'Erledigt!',
                    'meta' => ['actions' => count($actions)],
                ];

                $this->logConversationAction($userMessage, ['type' => 'multi'], $combinedResult, $model, $duration, $credits);

                $assistantMsg = implode('. ', $messages) . '. Kann ich noch etwas für dich tun?';
                $this->conversation[] = ['role' => 'user', 'content' => $userMessage];
                $this->conversation[] = ['role' => 'assistant', 'content' => $assistantMsg];

                if (str_contains($assistantMsg, '[END]')) {
                    $this->dispatch('conversation-ended');
                }

                $this->applyResult($combinedResult);
                $this->dispatch('agent:sent');

            } elseif (($parsed['type'] ?? 'unknown') === 'chat') {
                // ── Chat-Antwort: Log nur bei [END] ohne vorherige Aktion ──
                $chatMessage = $parsed['data']['message'] ?? 'Hmm, da bin ich überfragt.';

                $this->conversation[] = ['role' => 'user', 'content' => $userMessage];
                $this->conversation[] = ['role' => 'assistant', 'content' => $chatMessage];

                if (str_contains($chatMessage, '[END]')) {
                    // Gab es in dieser Session bereits eine geloggte Aktion?
                    $hadAction = collect($this->conversation)
                        ->where('role', 'assistant')
                        ->filter(fn($msg) => !str_contains($msg['content'], '[END]'))
                        ->count() > 1;

                    if (!$hadAction) {
                        $duration = round((microtime(true) - $startTime) * 1000);
                        $this->logConversationAction(
                            collect($this->conversation)
                                ->where('role', 'user')
                                ->first()['content'] ?? $userMessage,
                            ['type' => 'chat', 'data' => []],
                            ['status' => 'success', 'message' => 'Chat', 'meta' => []],
                            $model,
                            $duration,
                            5
                        );
                    }

                    $this->dispatch('conversation-ended');
                }

                $this->lastAction = null;

            } else {
                // ── Einzelne Aktion (event, note, task) ───────────────────────
                $result   = AgentActionService::handle($this->user, $parsed);
                $duration = round((microtime(true) - $startTime) * 1000);

                // Mehrdeutig → AI soll nachfragen (als Chat-Antwort behandeln)
                if ($result['status'] === 'ambiguous') {
                    $this->conversation[] = ['role' => 'user', 'content' => $userMessage];
                    $this->conversation[] = ['role' => 'assistant', 'content' => $result['message']];
                    $this->lastAction = null;

                } elseif ($result['status'] === 'conflict') {
                    $this->logConversationAction($userMessage, $parsed, $result, $model, $duration, 0);

                    $this->conversation[] = ['role' => 'user', 'content' => $userMessage];
                    $this->conversation[] = ['role' => 'assistant', 'content' => 'Es gibt einen Terminkonflikt. Ich zeige dir die Details.'];

                    $this->dispatch('openModal', 'agent.modals.conflict-modal', [
                        'data'          => $parsed['data'],
                        'meta'          => $result['meta'],
                        'originalInput' => $userMessage,
                    ]);

                    $this->dispatch('agent:sent');

                } else {
                    $credits = $this->calculateCredits($parsed, $duration, $usage);
                    $this->logConversationAction($userMessage, $parsed, $result, $model, $duration, $credits);

                    if ($result['status'] === 'success' && ($parsed['type'] ?? '') === 'event') {
                        $this->dispatch('eventCreated');

                        Activity::log(
                            $this->user->id,
                            Activity::TYPE_EVENT_CREATED,
                            Activity::localizedTitle('event_created_assistant', $this->user->locale ?? 'de'),
                            $result['meta']['title'] ?? null,
                            meta: [
                                'start'    => $result['meta']['start'] ?? null,
                                'credits'  => $credits,
                                'duration' => $result['meta']['duration'] ?? null,
                            ]
                        );
                    }

                    // Natürliche Bestätigung
                    $confirmMsg = $result['status'] === 'success'
                        ? ($result['message'] ?? 'Erledigt!') . ' Kann ich noch etwas für dich tun?'
                        : ($result['message'] ?? 'Da hat etwas nicht geklappt.');

                    $this->conversation[] = ['role' => 'user', 'content' => $userMessage];
                    $this->conversation[] = ['role' => 'assistant', 'content' => $confirmMsg];

                    if (str_contains($confirmMsg, '[END]')) {
                        $this->dispatch('conversation-ended');
                    }

                    $this->applyResult($result);
                }
            }

        } catch (\Throwable $e) {
            $duration = round((microtime(true) - $startTime) * 1000);

            $this->logConversationAction($userMessage, $parsed, [
                'status' => 'failed',
                'meta'   => ['error' => $e->getMessage()],
            ], $model, $duration, 0);

            $this->conversation[] = ['role' => 'user', 'content' => $userMessage];
            $this->conversation[] = ['role' => 'assistant', 'content' => 'Da ist leider etwas schiefgelaufen.'];

            $this->applyResult([
                'status'  => 'failed',
                'message' => 'Fehler bei der Verarbeitung',
                'meta'    => [],
            ]);
        }

        $this->dispatch('agent:sent');

        // TTS im selben Request mitsynthetisieren (spart einen Round-Trip)
        if ($withAudio && !empty($this->conversation)) {
            $lastMsg = end($this->conversation);
            if ($lastMsg['role'] === 'assistant') {
                $spokenText = trim(str_replace('[END]', '', $lastMsg['content']));
                if ($spokenText) {
                    $audio = AgentAIService::textToSpeech($spokenText, $aiConfig);
                    return ['audio' => $audio];
                }
            }
        }

        return null;
    }

    public function synthesize(string $text): array
    {
        $aiConfig = $this->plan?->ai_config ?? [];
        if (is_string($aiConfig)) {
            $aiConfig = json_decode($aiConfig, true);
        }

        $audio = AgentAIService::textToSpeech($text, $aiConfig);

        return ['audio' => $audio];
    }

    public function clearConversation(): void
    {
        $this->conversation = [];
        $this->lastAction = null;
        $this->conversationPromptTokens = 0;
        $this->conversationCompletionTokens = 0;
        $this->conversationTotalTokens = 0;
        $this->conversationCostUsd = 0;
    }

    public function handleAgentResult(array $result): void
    {
        $this->applyResult($result);
    }

    public function render()
    {
        return view('livewire.agent.index')->layout('layouts.app');
    }

    // ── Private ───────────────────────────────────────────────────────────

    private function extractChatTitle(string $userMessage): string
    {
        $farewells = [
            'nein danke', 'nein', 'danke', 'passt', 'das wars',
            'ok danke', 'okay danke', 'super danke', 'alles klar',
            'nichts mehr', 'tschüss', 'bye', 'ciao',
        ];

        $isGoodbye = in_array(strtolower(trim($userMessage)), $farewells);

        if ($isGoodbye && count($this->conversation) > 0) {
            foreach ($this->conversation as $msg) {
                if ($msg['role'] === 'user') {
                    return mb_substr($msg['content'], 0, 80);
                }
            }
        }

        return mb_substr($userMessage, 0, 80);
    }

    private function logConversationAction(
        string $userMessage,
        array $parsed,
        array $result,
        string $model,
        int $duration,
        int $credits,
    ): void {
        $input = match ($parsed['type']) {
            'event', 'event_update' => $parsed['data']['title'] ?? $userMessage,
            'note', 'note_update'   => mb_substr($parsed['data']['content'] ?? $userMessage, 0, 100),
            'task', 'task_update'   => $parsed['data']['title'] ?? $userMessage,
            'contact'               => $parsed['data']['name'] ?? $userMessage,
            'email'                 => 'E-Mail an ' . ($parsed['data']['contact'] ?? '') . ': ' . mb_substr($parsed['data']['subject'] ?? '', 0, 50),
            'multi'                 => $userMessage,
            'chat'                  => $this->extractChatTitle($userMessage),
            default                 => mb_substr($userMessage, 0, 200),
        };

        AgentLog::create([
            'user_id'           => $this->user->id,
            'type'              => $parsed['type'],
            'input'             => $input,
            'status'            => $result['status'],
            'output'            => $result['meta'] ?? null,
            'credits'           => $credits,
            'ai_response'       => $parsed,
            'model'             => $model,
            'duration_ms'       => $duration,
            'prompt_tokens'     => $this->conversationPromptTokens,
            'completion_tokens' => $this->conversationCompletionTokens,
            'total_tokens'      => $this->conversationTotalTokens,
            'cost_usd'          => $this->conversationCostUsd,
        ]);

        $this->recalcUsage();

        if ($this->limit > 0 && $this->usage >= $this->limit) {
            $this->dispatch('notify', [
                'type'    => 'warning',
                'title'   => 'Kontingent aufgebraucht',
                'message' => 'Dein Kontingent ist erschöpft. Upgrade auf Pro oder warte bis zum nächsten Monat.',
            ]);
        }
    }

    private function applyResult(array $result): void
    {
        $this->lastAction = [
            'status'  => $result['status'],
            'message' => $result['message'],
            'meta'    => $result['meta'] ?? [],
            'time'    => now(),
        ];

        $this->recalcUsage();
    }

    private function recalcUsage(): void
    {
        $this->user->refresh();

        if ($this->user->effective_limit === 0) {
            $this->usage        = 0;
            $this->usagePercent = 0;
            $this->limit        = 0;
            return;
        }

        $this->limit        = $this->user->effective_limit;
        $this->usage        = $this->user->effective_usage;
        $this->usagePercent = $this->user->usage_percent;
    }

    private function calculateCost(array $usage, string $model): float
    {
        $aiConfig = $this->plan?->ai_config ?? [];
        if (is_string($aiConfig)) {
            $aiConfig = json_decode($aiConfig, true);
        }

        $inputCost  = ($usage['prompt_tokens'] ?? 0) / 1000 * ($aiConfig['input_cost'] ?? 0.00015);
        $outputCost = ($usage['completion_tokens'] ?? 0) / 1000 * ($aiConfig['output_cost'] ?? 0.0006);

        return round($inputCost + $outputCost, 6);
    }

private function calculateCredits(array $parsed, int $duration, array $usage): int
    {
        // Flat-Basis + Output-Tokens. Kontext (prompt_tokens) wird ignoriert,
        // damit Credits nicht mit Kalendergröße skalieren. Cap bei 100.
        $completionTokens = (int) ($usage['completion_tokens'] ?? 0);
        $credits = 20 + (int) ceil($completionTokens * 0.3);

        return min(100, max(1, $credits));
    }
}
