<?php

namespace Modules\WhatsApp\Entities\Services;

use Illuminate\Support\Facades\DB;
use Modules\WhatsApp\Entities\WaContact;
use Modules\WhatsApp\Entities\WaConversation;
use Modules\WhatsApp\Entities\WaMessage;

/**
 * Deterministic "who am I talking to" step that runs BEFORE the AI on each
 * inbound message:
 *   - registered ERP contact  → personalise (greet by name), proceed to AI.
 *   - known guest (name given) → personalise with the captured name.
 *   - new guest                → ask for their name first, remember their
 *     original question, and answer it once they reply with a name.
 *
 * Returns a "persona" the responder injects into the prompt, or signals that it
 * already replied (asked for a name) so the AI should not run this turn.
 *
 * Conversation.meta keys used: awaiting_name(bool), guest_name(string),
 * pending_question(string).
 */
class WaCustomerJourney
{
    /**
     * @return array{
     *   proceed:bool, name:?string, registered:bool, contact_id:?int,
     *   question:string, just_named:bool
     * }
     */
    public function handle(WaMessage $inbound, WaConversation $conversation, string $businessName, ?string $effectiveText = null): array
    {
        $businessId = (int) $inbound->business_id;
        $waId = (string) $inbound->wa_id;
        $text = trim($effectiveText ?? (string) $inbound->body);

        // 1) Registered ERP contact → greet by name, no questions asked.
        $contact = $this->findContact($businessId, $waId);
        if ($contact) {
            // Link the WhatsApp identity to the ERP contact for future use.
            WaContact::where('business_id', $businessId)->where('wa_id', $waId)
                ->update(['contact_id' => $contact->id]);

            return $this->proceed($this->firstName($contact->name), true, $contact->id, $text);
        }

        // 2) Guest — do we already have their name?
        $meta = $conversation->meta ?? [];
        if (!empty($meta['guest_name'])) {
            return $this->proceed($meta['guest_name'], false, null, $text);
        }

        // 2a) We asked for their name last turn → treat this message as the name.
        if (!empty($meta['awaiting_name'])) {
            $name = $this->extractName($text);
            if ($name === null) {
                $this->reply($conversation, "Sorry, I didn't catch that 🙂 — could you tell me your name, please?");
                return $this->stop();
            }

            $pending = $meta['pending_question'] ?? '';
            unset($meta['awaiting_name'], $meta['pending_question']);
            $meta['guest_name'] = $name;
            $conversation->forceFill(['meta' => $meta])->save();
            WaContact::where('business_id', $businessId)->where('wa_id', $waId)->update(['name' => $name]);

            // If they had a real question, answer it now (the AI thanks them by name);
            // otherwise just greet and invite the question.
            if ($pending !== '' && !$this->looksLikeGreetingOnly($pending)) {
                return $this->proceed($name, false, null, $pending, true);
            }

            $this->reply($conversation, "Nice to meet you, {$name}! 😊 How can I help you today?");
            return $this->stop();
        }

        // 2b) First message from a new guest → ask for the name, remember the question.
        $meta['awaiting_name'] = true;
        $meta['pending_question'] = $text;
        $conversation->forceFill(['meta' => $meta])->save();

        $this->reply($conversation, "Hello! 👋 Welcome to {$businessName}. May I have your name, please, so I can help you better?");
        return $this->stop();
    }

    // ---- helpers ----

    private function proceed(?string $name, bool $registered, ?int $contactId, string $question, bool $justNamed = false): array
    {
        return [
            'proceed'    => true,
            'name'       => $name ?: null,
            'registered' => $registered,
            'contact_id' => $contactId,
            'question'   => $question,
            'just_named' => $justNamed,
        ];
    }

    private function stop(): array
    {
        return ['proceed' => false, 'name' => null, 'registered' => false, 'contact_id' => null, 'question' => '', 'just_named' => false];
    }

    private function findContact(int $businessId, string $waId)
    {
        $national = preg_replace('/^20/', '', $waId);
        if (strlen($national) < 7) {
            return null;
        }
        return DB::table('contacts')->where('business_id', $businessId)
            ->where('mobile', 'like', "%{$national}%")
            ->whereIn('type', ['customer', 'both'])
            ->first(['id', 'name']);
    }

    private function firstName(?string $name): ?string
    {
        $name = trim((string) $name);
        if ($name === '') {
            return null;
        }
        return explode(' ', $name)[0];
    }

    /** Best-effort name extraction from a free-text reply. */
    private function extractName(string $text): ?string
    {
        $t = trim($text);
        // Strip common lead-ins.
        $t = preg_replace('/^(my name is|i am|i\'m|this is|name\s*[:\-]|it\'s|its)\s+/i', '', $t);
        $t = trim($t, " .,!\t\"'");

        if ($t === '' || mb_strlen($t) > 40) {
            return null;
        }
        // Must contain letters and not look like a question.
        if (str_contains($t, '?') || !preg_match('/\p{L}/u', $t)) {
            return null;
        }
        // Take the first 1–3 words as the name.
        $words = preg_split('/\s+/', $t);
        return ucwords(mb_strtolower(implode(' ', array_slice($words, 0, 3))));
    }

    private function looksLikeGreetingOnly(string $text): bool
    {
        $t = mb_strtolower(trim($text));
        return in_array($t, ['hi', 'hello', 'hey', 'hallo', 'salam', 'سلام', 'مرحبا', 'hi there', 'good morning', 'good evening'], true)
            || mb_strlen($t) <= 2;
    }

    private function reply(WaConversation $conversation, string $body): void
    {
        (new WaSender())->send([
            'business_id' => $conversation->business_id,
            'channel_id'  => $conversation->channel_id,
            'to'          => $conversation->wa_id,
            'body'        => $body,
            'source'      => 'ai',
        ]);
    }
}
