<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\AgentLog;
use App\Services\AgentAIService;
use App\Services\AgentActionService;
use App\Services\AgentContextService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class AgentChatController extends Controller
{
    public function chat(Request $request): JsonResponse
    {
        $request->validate([
            'message' => 'required|string|max:2000',
            'conversation_history' => 'array',
            'conversation_history.*.role' => 'required_with:conversation_history|in:user,assistant',
            'conversation_history.*.content' => 'required_with:conversation_history|string',
            'with_audio' => 'boolean',
        ]);

        $user = $request->user();
        $user->load('subscription.plan');

        // Credit-Limit prüfen
        if ($user->effective_limit > 0 && $user->monthly_usage >= $user->effective_limit * 1.05) {
            return response()->json([
                'success' => false,
                'message' => 'Dein monatliches Credit-Limit ist erreicht.',
                'errors' => ['credits' => 'Limit überschritten'],
            ], 429);
        }

        $aiConfig = $user->subscription?->plan?->ai_config ?? [
            'model' => config('services.openai.model', 'gpt-4o-mini'),
            'temperature' => 0.5,
            'max_tokens' => 1500,
            'input_cost' => 0.00015,
            'output_cost' => 0.0006,
        ];

        // Konversation aufbauen
        $history = $request->input('conversation_history', []);
        $history[] = ['role' => 'user', 'content' => $request->message];

        // User-Kontext erstellen (geteilter Service → Web + API identisch)
        $userContext = app(AgentContextService::class)->build($user);

        $startTime = microtime(true);

        // AI aufrufen
        \Log::info('AgentChat: Calling AI', [
            'user_id' => $user->id,
            'message' => mb_substr($request->message, 0, 100),
            'history_count' => count($history),
            'model' => $aiConfig['model'] ?? 'default',
        ]);

        try {
            $aiResult = AgentAIService::chat($history, $aiConfig, $userContext);
            \Log::info('AgentChat: AI result', [
                'type' => $aiResult['type'] ?? 'unknown',
                'has_message' => !empty($aiResult['data']['message'] ?? $aiResult['message'] ?? ''),
            ]);
        } catch (\Throwable $e) {
            \Log::error('AgentChat: AI exception', [
                'error' => $e->getMessage(),
                'class' => get_class($e),
            ]);
            report($e);
            return response()->json([
                'success' => true,
                'data' => [
                    'message' => 'Entschuldigung, ich konnte gerade nicht antworten. Bitte versuche es nochmal.',
                    'action' => null,
                    'type' => 'chat',
                    'credits_used' => 0,
                ],
            ]);
        }

        // _error-Flag: OpenAI API down oder Timeout — 0 Credits, Fehler loggen
        if (!empty($aiResult['_error'])) {
            $durationMs = (int) ((microtime(true) - $startTime) * 1000);
            AgentLog::create([
                'user_id'           => $user->id,
                'type'              => 'chat',
                'input'             => mb_substr($request->message, 0, 100),
                'status'            => 'error',
                'output'            => null,
                'credits'           => 0,
                'ai_response'       => null,
                'model'             => $aiConfig['model'] ?? null,
                'duration_ms'       => $durationMs,
                'prompt_tokens'     => 0,
                'completion_tokens' => 0,
                'total_tokens'      => 0,
                'cost_usd'          => 0,
            ]);
            return response()->json([
                'success' => true,
                'data' => [
                    'message'      => $aiResult['data']['message'] ?? 'Entschuldigung, bitte versuche es nochmal.',
                    'action'       => null,
                    'type'         => 'chat',
                    'credits_used' => 0,
                    'usage' => [
                        'credits_used'  => $user->monthly_usage,
                        'credits_limit' => $user->effective_limit,
                        'usage_percent' => $user->usage_percent,
                    ],
                ],
            ]);
        }

        // AgentAIService gibt direkt das parsed-Objekt zurück (kein 'parsed'-Wrapper)
        // Keys: type, data, _usage, _multi (bei Multi-Actions)
        $parsed = $aiResult;
        $usage = $aiResult['_usage'] ?? [];

        $durationMs = (int) ((microtime(true) - $startTime) * 1000);

        $actionResult = null;
        $assistantMessage = $parsed['data']['message']
            ?? $parsed['message']
            ?? $parsed['text']
            ?? '';

        // Aktion ausführen falls vorhanden
        try {
            if (isset($parsed['_multi'])) {
                $actionService = new AgentActionService();
                $results = [];
                foreach ($parsed['_multi'] as $action) {
                    $results[] = $actionService->handle($user, $action);
                }
                $actionResult = [
                    'status' => collect($results)->every(fn ($r) => $r['status'] === 'success') ? 'success' : 'partial',
                    'results' => $results,
                ];
            } elseif (isset($parsed['type']) && $parsed['type'] !== 'chat') {
                $actionService = new AgentActionService();
                $actionResult = $actionService->handle($user, $parsed);
            }
        } catch (\Throwable $e) {
            report($e);
            $actionResult = ['status' => 'error', 'message' => 'Aktion fehlgeschlagen'];
        }

        // Wenn Aktion ausgeführt aber keine Message von der AI → Action-Message verwenden
        if (empty($assistantMessage) && $actionResult) {
            $assistantMessage = $actionResult['message'] ?? 'Erledigt!';
        }

        // Letzter Schutz: JSON darf NIE vorgelesen werden
        if (is_string($assistantMessage) && $assistantMessage !== '') {
            $trim = ltrim($assistantMessage);
            $isJsonLike = $trim !== '' && ($trim[0] === '{' || $trim[0] === '[')
                || str_contains($assistantMessage, '"type":')
                || str_contains($assistantMessage, '"data":');

            if ($isJsonLike) {
                \Log::warning('AgentChat: JSON leaked to assistant message — replaced', [
                    'preview' => mb_substr($assistantMessage, 0, 200),
                ]);
                $assistantMessage = $actionResult['message'] ?? 'Erledigt!';
            }
        }

        // Credits berechnen — Flat-Rate-Logik
        // - Aktionen: tokenbasiert (wie bisher)
        // - Erster Chat einer Session (history leer): pauschal 5 Credits
        // - Folge-Chat-Nachrichten: 0 Credits, kein Log
        $type = $parsed['type'] ?? 'chat';
        $isAction = $type !== 'chat';
        $historyCount = count($request->input('conversation_history', []));
        $shouldLog = true;

        if ($isAction) {
            $credits = (($actionResult['status'] ?? '') === 'error')
                ? 0
                : $this->calculateCredits($usage, $aiConfig, $type);
        } elseif ($historyCount === 0) {
            $credits = 5;
        } else {
            $credits = 0;
            $shouldLog = false;
        }

        if ($shouldLog) {
            // Input für Log bestimmen (wie im Web)
            $logInput = match ($type) {
                'chat'                  => 'Konversation',
                'event', 'event_update' => $parsed['data']['title'] ?? $request->message,
                'note', 'note_update'   => mb_substr($parsed['data']['content'] ?? $request->message, 0, 100),
                'task', 'task_update'   => $parsed['data']['title'] ?? $request->message,
                'contact'               => $parsed['data']['name'] ?? $request->message,
                'email'                 => 'E-Mail an ' . ($parsed['data']['contact'] ?? '') . ': ' . mb_substr($parsed['data']['subject'] ?? '', 0, 50),
                'multi'                 => $request->message,
                default                 => mb_substr($request->message, 0, 200),
            };

            $logStatus = ($actionResult['status'] ?? 'success') === 'error' ? 'failed' : ($actionResult['status'] ?? 'success');

            AgentLog::create([
                'user_id' => $user->id,
                'type' => $type,
                'input' => $logInput,
                'status' => $logStatus,
                'output' => $actionResult['meta'] ?? $actionResult ?? null,
                'credits' => $credits,
                'ai_response' => $parsed,
                'model' => $aiConfig['model'] ?? null,
                'duration_ms' => $durationMs,
                'prompt_tokens' => $usage['prompt_tokens'] ?? 0,
                'completion_tokens' => $usage['completion_tokens'] ?? 0,
                'total_tokens' => $usage['total_tokens'] ?? 0,
                'cost_usd' => $this->calculateCostUsd($usage, $aiConfig),
            ]);
        }

        // TTS falls gewünscht (Fehler darf Chat nicht blockieren)
        $audio = null;
        if ($request->boolean('with_audio') && $assistantMessage) {
            try {
                $audio = AgentAIService::textToSpeech($assistantMessage, $aiConfig);
            } catch (\Throwable $e) {
                report($e);
            }
        }

        // Usage neu berechnen
        $user->refresh();

        $responseData = [
            'message' => $assistantMessage,
            'action' => $actionResult,
            'type' => $parsed['type'] ?? 'chat',
            'credits_used' => $credits,
            'usage' => [
                'credits_used' => $user->monthly_usage,
                'credits_limit' => $user->effective_limit,
                'usage_percent' => $user->usage_percent,
            ],
        ];

        if ($audio) {
            $responseData['audio'] = $audio;
        }

        return response()->json([
            'success' => true,
            'data' => $responseData,
        ]);
    }

    public function synthesize(Request $request): JsonResponse
    {
        $request->validate([
            'text'   => 'required|string|max:500',
            'locale' => 'nullable|string',
        ]);

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

        // Voice je nach Locale wählen
        $voice = str_starts_with($request->input('locale', 'de'), 'en')
            ? 'shimmer'
            : 'nova';

        $overrideConfig = array_merge($aiConfig, ['tts_voice' => $voice]);
        $audio = AgentAIService::textToSpeech($request->text, $overrideConfig);

        return response()->json([
            'success' => true,
            'data'    => ['audio' => $audio],
        ]);
    }


    private function calculateCredits(array $usage, array $aiConfig, string $type): 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));
    }

    private function calculateCostUsd(array $usage, array $aiConfig): float
    {
        $inputCost = $aiConfig['input_cost'] ?? 0.00015;
        $outputCost = $aiConfig['output_cost'] ?? 0.0006;

        return (($usage['prompt_tokens'] ?? 0) / 1000) * $inputCost
             + (($usage['completion_tokens'] ?? 0) / 1000) * $outputCost;
    }

    public function logs(Request $request): JsonResponse
    {
        $logs = $request->user()
            ->agentLogs()
            ->latest()
            ->take(20)
            ->get(['id', 'type', 'input', 'output', 'status', 'credits', 'duration_ms', 'created_at']);

        return response()->json([
            'success' => true,
            'data'    => $logs,
        ]);
    }
}
