<?php

namespace Modules\Bms\Services\Ai;

use Illuminate\Support\Facades\DB;
use Modules\Bms\Entities\BmsBooking;
use Modules\Bms\Entities\BmsHall;
use Modules\Bms\Entities\BmsLead;
use Modules\Bms\Entities\BmsTask;

/**
 * BMS operations assistant. Grounds a shared-engine LLM (AiCore) on a
 * whitelisted, read-only snapshot of the business's banquet data, so answers
 * stay factual and scoped. No write tools are exposed.
 */
class BmsAssistant
{
    /**
     * @return array ['ok'=>bool, 'text'=>string, 'error'=>?string]
     */
    public function answer(int $businessId, string $question, string $locale = 'en'): array
    {
        $provider = '\Modules\AiCore\Entities\AiProvider';
        $client = '\Modules\AiCore\Entities\Services\AiClient';
        if (! class_exists($provider) || ! class_exists($client)) {
            return ['ok' => false, 'text' => '', 'error' => 'ai_core_absent'];
        }

        $settings = $provider::forBusiness($businessId);
        if (empty($settings->enabled)) {
            return ['ok' => false, 'text' => '', 'error' => 'ai_disabled'];
        }

        $context = $this->context($businessId);
        $lang = $locale === 'ar' ? 'Arabic' : 'English';

        $system = "You are the operations assistant for a banquet/wedding business. "
            . "Answer ONLY from the CONTEXT below; if the data is not present, say you don't have it. "
            . "Be concise and practical. Reply in {$lang}. Never invent figures.";
        $user = "CONTEXT:\n{$context}\n\nQUESTION: {$question}";

        $res = app($client)->chat($settings, $system, $user, ['module' => 'bms', 'feature' => 'assistant']);

        return ['ok' => (bool) ($res['ok'] ?? false), 'text' => $res['text'] ?? '', 'error' => $res['error'] ?? null];
    }

    /** Whitelisted, bounded snapshot of the banquet operation. */
    protected function context(int $businessId): string
    {
        $today = now()->toDateString();
        $horizon = now()->addDays(14)->toDateString();

        // Pipeline by stage.
        $stages = BmsLead::where('business_id', $businessId)
            ->select('stage', DB::raw('count(*) c'))->groupBy('stage')->pluck('c', 'stage');

        // Upcoming bookings.
        $bookings = BmsBooking::where('business_id', $businessId)
            ->whereDate('event_date', '>=', $today)->whereDate('event_date', '<=', $horizon)
            ->orderBy('event_date')->limit(20)
            ->get(['booking_no', 'event_date', 'status', 'event_type', 'attendees', 'total_amount']);

        // Revenue (BMS invoices).
        $rev = DB::table('transactions')
            ->where('business_id', $businessId)->where('source', 'bms')->where('type', 'sell')
            ->selectRaw('coalesce(sum(final_total),0) invoiced')->first();
        $collected = DB::table('transaction_payments')
            ->join('transactions', 'transactions.id', '=', 'transaction_payments.transaction_id')
            ->where('transactions.business_id', $businessId)->where('transactions.source', 'bms')
            ->where('transaction_payments.is_return', 0)
            ->sum('transaction_payments.amount');

        // Tasks.
        $openTasks = BmsTask::where('business_id', $businessId)->where('status', '!=', 'done')->count();
        $overdue = BmsTask::where('business_id', $businessId)->where('status', '!=', 'done')
            ->whereNotNull('due_at')->where('due_at', '<', now())->count();

        // Halls.
        $halls = BmsHall::where('business_id', $businessId)->where('is_active', true)->count();

        $lines = [];
        $lines[] = 'Today: ' . $today;
        $lines[] = 'Active halls: ' . $halls;
        $lines[] = 'Lead pipeline: ' . ($stages->isEmpty() ? 'none' : $stages->map(fn ($c, $s) => "$s=$c")->implode(', '));
        $lines[] = 'Revenue (BMS): invoiced=' . number_format((float) $rev->invoiced, 2) . ', collected=' . number_format((float) $collected, 2)
            . ', outstanding=' . number_format((float) $rev->invoiced - (float) $collected, 2);
        $lines[] = 'Tasks: open=' . $openTasks . ', overdue=' . $overdue;
        $lines[] = 'Upcoming bookings (' . $today . '..' . $horizon . '):';
        if ($bookings->isEmpty()) {
            $lines[] = '  (none)';
        } else {
            foreach ($bookings as $b) {
                $lines[] = sprintf('  - %s | %s | %s | %s | %d guests | %s',
                    $b->booking_no, optional($b->event_date)->toDateString() ?? $b->event_date, $b->status,
                    $b->event_type, (int) $b->attendees, number_format((float) $b->total_amount, 0));
            }
        }

        return implode("\n", $lines);
    }
}
