<?php

declare(strict_types=1);

namespace App\Services;

use App\Core\Database;
use App\Models\ConversationModel;
use App\Models\KnowledgeBaseModel;

/**
 * AiToolService
 *
 * Every function the AI Assistant can call, as a plain PHP method with
 * no dependency on OpenAI or any LLM — this is what makes it fully
 * testable without a live API call. AiAssistantService is the only
 * caller: it receives a tool_call from the model (name + JSON
 * arguments) and dispatches here via call(). Keeping this layer
 * separate from the OpenAI wire format means the tools themselves are
 * exactly as testable as any other service in this codebase.
 */
final class AiToolService
{
    /** @return array{success:bool} plus tool-specific keys — always JSON-encodable, this is what gets sent back to the model as the tool result. */
    public function call(string $toolName, array $arguments): array
    {
        return match ($toolName) {
            'search_customers' => $this->searchCustomers($arguments),
            'search_leads' => $this->searchLeads($arguments),
            'book_appointment' => $this->bookAppointment($arguments),
            'generate_report' => $this->generateReport($arguments),
            'answer_question' => $this->answerQuestion($arguments),
            'summarize_conversation' => $this->summarizeConversation($arguments),
            default => ['success' => false, 'error' => "Unknown tool: {$toolName}"],
        };
    }

    /** @return array<int,array{name:string,description:string,parameters:array}> OpenAI-format tool definitions — see AiAssistantService. */
    public static function toolDefinitions(): array
    {
        return [
            [
                'name' => 'search_customers',
                'description' => 'Search customers by name, email, or phone.',
                'parameters' => ['type' => 'object', 'properties' => ['query' => ['type' => 'string']], 'required' => ['query']],
            ],
            [
                'name' => 'search_leads',
                'description' => 'Search leads by name, email, or phone.',
                'parameters' => ['type' => 'object', 'properties' => ['query' => ['type' => 'string']], 'required' => ['query']],
            ],
            [
                'name' => 'book_appointment',
                'description' => 'Book a new appointment for a customer or lead.',
                'parameters' => [
                    'type' => 'object',
                    'properties' => [
                        'customer_id' => ['type' => 'integer'],
                        'lead_id' => ['type' => 'integer'],
                        'business_line_id' => ['type' => 'integer'],
                        'scheduled_start' => ['type' => 'string', 'description' => 'Y-m-d H:i:s'],
                        'scheduled_end' => ['type' => 'string', 'description' => 'Y-m-d H:i:s'],
                        'assigned_staff_id' => ['type' => 'integer'],
                    ],
                    'required' => ['business_line_id', 'scheduled_start', 'scheduled_end'],
                ],
            ],
            [
                'name' => 'generate_report',
                'description' => 'Generate a business report: overview, leads_pipeline, revenue, appointments, or conversations.',
                'parameters' => [
                    'type' => 'object',
                    'properties' => ['report_type' => ['type' => 'string'], 'days' => ['type' => 'integer']],
                    'required' => ['report_type'],
                ],
            ],
            [
                'name' => 'answer_question',
                'description' => 'Search the knowledge base for an answer to a question.',
                'parameters' => ['type' => 'object', 'properties' => ['question' => ['type' => 'string']], 'required' => ['question']],
            ],
            [
                'name' => 'summarize_conversation',
                'description' => 'Summarize a past conversation by its id.',
                'parameters' => ['type' => 'object', 'properties' => ['conversation_id' => ['type' => 'integer']], 'required' => ['conversation_id']],
            ],
        ];
    }

    private function searchCustomers(array $args): array
    {
        $query = (string) ($args['query'] ?? '');
        $stmt = Database::connection()->prepare(
            "SELECT id, first_name, last_name, email, phone, status FROM customers
             WHERE deleted_at IS NULL AND (first_name LIKE :q OR last_name LIKE :q OR email LIKE :q OR phone LIKE :q)
             LIMIT 10"
        );
        $stmt->execute(['q' => '%' . $query . '%']);

        return ['success' => true, 'customers' => $stmt->fetchAll()];
    }

    private function searchLeads(array $args): array
    {
        $query = (string) ($args['query'] ?? '');
        $stmt = Database::connection()->prepare(
            "SELECT id, first_name, last_name, email, phone FROM leads
             WHERE deleted_at IS NULL AND merged_into_lead_id IS NULL
               AND (first_name LIKE :q OR last_name LIKE :q OR email LIKE :q OR phone LIKE :q)
             LIMIT 10"
        );
        $stmt->execute(['q' => '%' . $query . '%']);

        return ['success' => true, 'leads' => $stmt->fetchAll()];
    }

    private function bookAppointment(array $args): array
    {
        if (empty($args['customer_id']) && empty($args['lead_id'])) {
            return ['success' => false, 'error' => 'Either customer_id or lead_id is required.'];
        }

        return (new AppointmentService())->book([
            'business_line_id' => $args['business_line_id'],
            'customer_id' => $args['customer_id'] ?? null,
            'lead_id' => $args['lead_id'] ?? null,
            'assigned_staff_id' => $args['assigned_staff_id'] ?? null,
            'scheduled_start' => $args['scheduled_start'],
            'scheduled_end' => $args['scheduled_end'],
            'status' => 'scheduled',
        ], isset($args['_acting_user_id']) && (int) $args['_acting_user_id'] > 0 ? (int) $args['_acting_user_id'] : null);
    }

    private function generateReport(array $args): array
    {
        $reportType = (string) ($args['report_type'] ?? 'overview');
        $days = (int) ($args['days'] ?? 30);
        $reports = new ReportService();

        $report = match ($reportType) {
            'leads_pipeline' => $reports->leadsPipelineReport(null, $days),
            'revenue' => $reports->revenueReport(null, $days),
            'appointments' => $reports->appointmentsReport(null, $days),
            'conversations' => $reports->conversationsReport($days),
            default => $reports->overviewReport(null, $days),
        };

        return ['success' => true, 'report' => $report];
    }

    private function answerQuestion(array $args): array
    {
        $question = (string) ($args['question'] ?? '');
        $results = (new KnowledgeBaseModel())->search($question);

        if ($results === []) {
            return ['success' => true, 'found' => false, 'message' => 'No matching knowledge base article found.'];
        }

        return ['success' => true, 'found' => true, 'answer' => $results[0]['answer'], 'source_question' => $results[0]['question']];
    }

    private function summarizeConversation(array $args): array
    {
        $conversationId = (int) ($args['conversation_id'] ?? 0);
        $model = new ConversationModel();
        $messages = $model->messages($conversationId);

        if ($messages === []) {
            return ['success' => false, 'error' => 'Conversation not found or has no messages.'];
        }

        $transcript = implode("\n", array_map(fn ($m) => "{$m['sender']}: {$m['message']}", $messages));

        return ['success' => true, 'message_count' => count($messages), 'transcript' => $transcript];
    }
}