<?php

declare(strict_types=1);

namespace App\Services;

use App\Models\AiPromptModel;
use App\Models\ConversationModel;

/**
 * AiAssistantService
 *
 * The internal, staff-facing AI Assistant: Search Customers, Search
 * Leads, Book Appointments, Generate Reports, Answer Questions,
 * Summarize Conversations — all six are real AiToolService methods,
 * not mocked. This class's only job is the OpenAI tool-calling loop:
 * send messages, if the model wants a tool, run it via AiToolService
 * and feed the result back, repeat until the model responds with plain
 * text. Capped at MAX_TOOL_ITERATIONS so a misbehaving model can't loop
 * forever.
 */
final class AiAssistantService
{
    private const MAX_TOOL_ITERATIONS = 5;
    private const DEFAULT_SYSTEM_PROMPT = <<<'PROMPT'
        You are the internal AI Assistant for A&B Hub, used by staff at A&B Homecare Services and A&B Cleaner Janitorial Services. You can search customers and leads, book appointments, generate reports, answer questions from the knowledge base, and summarize past conversations. Be concise and professional. Always confirm details before booking an appointment.
        PROMPT;

    public function __construct(
        private readonly OpenAiClient $openAi = new OpenAiClient(),
        private readonly AiToolService $tools = new AiToolService(),
        private readonly AiPromptModel $prompts = new AiPromptModel(),
        private readonly ConversationModel $conversations = new ConversationModel()
    ) {
    }

    /**
     * @param array<int,array{role:string,content:string}> $history Prior turns in this conversation (role: 'user'|'assistant')
     * @return array{success:bool, reply?:string, error?:string, tool_calls_made?:array}
     */
    public function ask(string $userMessage, array $history, int $actingUserId, int $businessLineId): array
    {
        if (!$this->openAi->isConfigured()) {
            return ['success' => false, 'error' => 'OpenAI is not connected. Configure it from Admin > Integrations.'];
        }

        $systemPrompt = $this->prompts->activeFor('ai_assistant', $businessLineId)['system_prompt'] ?? self::DEFAULT_SYSTEM_PROMPT;

        $messages = [['role' => 'system', 'content' => $systemPrompt]];
        foreach ($history as $turn) {
            $messages[] = ['role' => $turn['role'], 'content' => $turn['content']];
        }
        $messages[] = ['role' => 'user', 'content' => $userMessage];

        $toolCallsMade = [];

        for ($i = 0; $i < self::MAX_TOOL_ITERATIONS; $i++) {
            $result = $this->openAi->chat($messages, AiToolService::toolDefinitions());

            if (!$result['success']) {
                return ['success' => false, 'error' => $result['error']];
            }

            $message = $result['message'];
            $toolCalls = $message['tool_calls'] ?? [];

            if ($toolCalls === []) {
                return [
                    'success' => true,
                    'reply' => (string) ($message['content'] ?? ''),
                    'tool_calls_made' => $toolCallsMade,
                ];
            }

            $messages[] = $message;

            foreach ($toolCalls as $toolCall) {
                $functionName = $toolCall['function']['name'];
                $arguments = json_decode((string) $toolCall['function']['arguments'], true) ?? [];
                $arguments['_acting_user_id'] = $actingUserId;

                $toolResult = $this->tools->call($functionName, $arguments);
                $toolCallsMade[] = ['name' => $functionName, 'arguments' => $arguments, 'result' => $toolResult];

                $messages[] = [
                    'role' => 'tool',
                    'tool_call_id' => $toolCall['id'],
                    'content' => json_encode($toolResult),
                ];
            }
        }

        return ['success' => false, 'error' => 'The assistant took too many steps without finishing — please rephrase your request.'];
    }

    /** Logs one full ask() exchange to the conversations/conversation_messages tables — call after ask() returns, from the controller. */
    public function logExchange(?int $conversationId, int $businessLineId, int $userId, string $userMessage, string $reply): int
    {
        if ($conversationId === null) {
            $conversationId = $this->conversations->start('ai_assistant', $businessLineId, "staff:{$userId}");
        }

        $this->conversations->addMessage($conversationId, 'visitor', $userMessage); // 'visitor' = the staff member asking, reusing the existing sender enum
        $this->conversations->addMessage($conversationId, 'bot', $reply);

        return $conversationId;
    }
}
