<?php

namespace Tests\Feature;

use App\Models\ChannelIntegration;
use App\Models\Contact;
use App\Models\Conversation;
use App\Models\Intent;
use App\Models\IntentPhrase;
use App\Models\Membership;
use App\Models\Message;
use App\Models\Organization;
use App\Models\ResponseTemplate;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;

class ChannelIntegrationTest extends TestCase
{
    use RefreshDatabase;

    public function test_channels_settings_page_shows_facebook_and_whatsapp_connections(): void
    {
        $user = User::factory()->create();
        $organization = Organization::factory()->create();

        Membership::factory()->create([
            'organization_id' => $organization->id,
            'user_id' => $user->id,
        ]);

        $response = $this->actingAs($user)->get(route('settings.channels.index'));

        $response->assertOk();
        $response->assertSee('Facebook Messenger');
        $response->assertSee('WhatsApp Cloud API');
        $response->assertSee('/api/webhooks/meta/facebook');
        $response->assertSee('/api/webhooks/meta/whatsapp');
    }

    public function test_channel_settings_can_save_facebook_connection(): void
    {
        $user = User::factory()->create();
        $organization = Organization::factory()->create();

        Membership::factory()->create([
            'organization_id' => $organization->id,
            'user_id' => $user->id,
        ]);

        $response = $this->actingAs($user)->put(route('settings.channels.update', 'facebook'), [
            'enabled' => '1',
            'name' => 'VejalNai Page',
            'external_id' => 'page-123',
            'webhook_verify_token' => 'verify-token',
            'access_token' => 'page-token',
            'app_secret' => 'app-secret',
            'signature_verification' => 'off',
            'default_locale' => 'bn',
        ]);

        $response->assertRedirect(route('settings.channels.index'));

        $this->assertDatabaseHas('channel_integrations', [
            'organization_id' => $organization->id,
            'provider' => 'facebook',
            'name' => 'VejalNai Page',
            'external_id' => 'page-123',
            'webhook_verify_token' => 'verify-token',
            'enabled' => true,
        ]);
    }

    public function test_facebook_webhook_verifies_and_processes_message(): void
    {
        $organization = $this->organizationWithAnswer();
        ChannelIntegration::query()->create([
            'organization_id' => $organization->id,
            'provider' => 'facebook',
            'name' => 'Facebook Page',
            'external_id' => 'page-123',
            'webhook_verify_token' => 'verify-token',
            'enabled' => true,
            'settings' => ['default_locale' => 'bn', 'signature_verification' => 'off'],
        ]);

        $verify = $this->get('/api/webhooks/meta/facebook?hub.mode=subscribe&hub.verify_token=verify-token&hub.challenge=challenge-123');

        $verify->assertOk();
        $verify->assertSee('challenge-123');

        $response = $this->postJson('/api/webhooks/meta/facebook', [
            'object' => 'page',
            'entry' => [[
                'id' => 'page-123',
                'messaging' => [[
                    'sender' => ['id' => 'psid-1'],
                    'recipient' => ['id' => 'page-123'],
                    'message' => ['mid' => 'm-1', 'text' => 'delivery charge koto?'],
                ]],
            ]],
        ]);

        $response->assertOk();
        $response->assertJsonPath('data.provider', 'facebook');
        $response->assertJsonPath('data.processed', 1);

        $this->assertDatabaseHas('contacts', [
            'organization_id' => $organization->id,
            'channel' => 'facebook',
            'external_id' => 'psid-1',
        ]);
        $this->assertDatabaseHas('conversations', [
            'organization_id' => $organization->id,
            'channel' => 'facebook',
        ]);
        $this->assertDatabaseHas('messages', [
            'sender_type' => 'bot',
            'body' => 'Dhakar vitore delivery charge 80 taka.',
        ]);
    }

    public function test_whatsapp_webhook_processes_text_message(): void
    {
        $organization = $this->organizationWithAnswer();
        ChannelIntegration::query()->create([
            'organization_id' => $organization->id,
            'provider' => 'whatsapp',
            'name' => 'WhatsApp Business',
            'external_id' => 'phone-number-id-1',
            'webhook_verify_token' => 'verify-token',
            'enabled' => true,
            'settings' => ['default_locale' => 'bn', 'signature_verification' => 'off'],
        ]);

        $response = $this->postJson('/api/webhooks/meta/whatsapp', [
            'object' => 'whatsapp_business_account',
            'entry' => [[
                'id' => 'waba-1',
                'changes' => [[
                    'value' => [
                        'metadata' => ['phone_number_id' => 'phone-number-id-1'],
                        'contacts' => [[
                            'wa_id' => '8801711111111',
                            'profile' => ['name' => 'WhatsApp Customer'],
                        ]],
                        'messages' => [[
                            'from' => '8801711111111',
                            'id' => 'wamid-1',
                            'type' => 'text',
                            'text' => ['body' => 'delivery charge koto?'],
                        ]],
                    ],
                    'field' => 'messages',
                ]],
            ]],
        ]);

        $response->assertOk();
        $response->assertJsonPath('data.provider', 'whatsapp');
        $response->assertJsonPath('data.processed', 1);

        $this->assertDatabaseHas('contacts', [
            'organization_id' => $organization->id,
            'channel' => 'whatsapp',
            'external_id' => '8801711111111',
            'name' => 'WhatsApp Customer',
            'phone' => '8801711111111',
        ]);
        $this->assertDatabaseHas('conversations', [
            'organization_id' => $organization->id,
            'channel' => 'whatsapp',
        ]);
        $this->assertDatabaseHas('messages', [
            'sender_type' => 'bot',
            'body' => 'Dhakar vitore delivery charge 80 taka.',
        ]);
    }

    public function test_duplicate_meta_webhook_event_is_ignored(): void
    {
        $organization = $this->organizationWithAnswer();
        ChannelIntegration::query()->create([
            'organization_id' => $organization->id,
            'provider' => 'facebook',
            'name' => 'Facebook Page',
            'external_id' => 'page-123',
            'webhook_verify_token' => 'verify-token',
            'enabled' => true,
            'settings' => ['default_locale' => 'bn', 'signature_verification' => 'off'],
        ]);

        $payload = [
            'object' => 'page',
            'entry' => [[
                'id' => 'page-123',
                'messaging' => [[
                    'sender' => ['id' => 'psid-dup'],
                    'recipient' => ['id' => 'page-123'],
                    'message' => ['mid' => 'm-duplicate', 'text' => 'delivery charge koto?'],
                ]],
            ]],
        ];

        $first = $this->postJson('/api/webhooks/meta/facebook', $payload);
        $second = $this->postJson('/api/webhooks/meta/facebook', $payload);

        $first->assertJsonPath('data.processed', 1);
        $second->assertJsonPath('data.processed', 0);

        $this->assertSame(1, Message::query()
            ->where('provider', 'facebook')
            ->where('provider_message_id', 'm-duplicate')
            ->count());
    }

    public function test_facebook_webhook_sends_bot_reply_back_to_customer(): void
    {
        Http::fake([
            'https://graph.facebook.com/*' => Http::response(['message_id' => 'bot-out-1'], 200),
        ]);

        $organization = $this->organizationWithAnswer();
        ChannelIntegration::query()->create([
            'organization_id' => $organization->id,
            'provider' => 'facebook',
            'name' => 'Facebook Page',
            'external_id' => 'page-123',
            'webhook_verify_token' => 'verify-token',
            'access_token' => 'page-token',
            'enabled' => true,
            'settings' => ['default_locale' => 'bn', 'signature_verification' => 'off'],
        ]);

        $response = $this->postJson('/api/webhooks/meta/facebook', [
            'object' => 'page',
            'entry' => [[
                'id' => 'page-123',
                'messaging' => [[
                    'sender' => ['id' => 'psid-bot'],
                    'recipient' => ['id' => 'page-123'],
                    'message' => ['mid' => 'm-bot-reply', 'text' => 'delivery charge koto?'],
                ]],
            ]],
        ]);

        $response->assertOk();
        Http::assertSent(fn ($request): bool => $request->url() === 'https://graph.facebook.com/v23.0/page-123/messages'
            && $request['recipient']['id'] === 'psid-bot'
            && $request['message']['text'] === 'Dhakar vitore delivery charge 80 taka.');

        $this->assertDatabaseHas('messages', [
            'sender_type' => 'bot',
            'body' => 'Dhakar vitore delivery charge 80 taka.',
            'provider' => 'facebook',
            'provider_message_id' => 'bot-out-1',
            'delivery_status' => 'sent',
        ]);
    }

    public function test_human_reply_is_sent_to_facebook_channel(): void
    {
        Http::fake([
            'https://graph.facebook.com/*' => Http::response(['message_id' => 'out-facebook-1'], 200),
        ]);

        [$user, $organization, $conversation] = $this->externalConversation('facebook', 'psid-1');

        ChannelIntegration::query()->create([
            'organization_id' => $organization->id,
            'provider' => 'facebook',
            'name' => 'Facebook Page',
            'external_id' => 'page-123',
            'webhook_verify_token' => 'verify-token',
            'access_token' => 'page-token',
            'enabled' => true,
            'settings' => ['signature_verification' => 'off'],
        ]);

        $response = $this->actingAs($user)->post(route('conversations.messages.store', $conversation), [
            'body' => 'Hello from support',
        ]);

        $response->assertRedirect();
        Http::assertSent(fn ($request): bool => $request->url() === 'https://graph.facebook.com/v23.0/page-123/messages'
            && $request['recipient']['id'] === 'psid-1'
            && $request['message']['text'] === 'Hello from support');

        $this->assertDatabaseHas('messages', [
            'conversation_id' => $conversation->id,
            'sender_type' => 'human',
            'body' => 'Hello from support',
            'provider' => 'facebook',
            'provider_message_id' => 'out-facebook-1',
            'delivery_status' => 'sent',
        ]);
    }

    public function test_human_reply_is_sent_to_whatsapp_channel(): void
    {
        Http::fake([
            'https://graph.facebook.com/*' => Http::response(['messages' => [['id' => 'wamid-out-1']]], 200),
        ]);

        [$user, $organization, $conversation] = $this->externalConversation('whatsapp', '8801711111111');

        ChannelIntegration::query()->create([
            'organization_id' => $organization->id,
            'provider' => 'whatsapp',
            'name' => 'WhatsApp Business',
            'external_id' => 'phone-number-id-1',
            'webhook_verify_token' => 'verify-token',
            'access_token' => 'whatsapp-token',
            'enabled' => true,
            'settings' => ['phone_number_id' => 'phone-number-id-1', 'signature_verification' => 'off'],
        ]);

        $response = $this->actingAs($user)->post(route('conversations.messages.store', $conversation), [
            'body' => 'Hello on WhatsApp',
        ]);

        $response->assertRedirect();
        Http::assertSent(fn ($request): bool => $request->url() === 'https://graph.facebook.com/v23.0/phone-number-id-1/messages'
            && $request['messaging_product'] === 'whatsapp'
            && $request['to'] === '8801711111111'
            && $request['text']['body'] === 'Hello on WhatsApp');

        $this->assertDatabaseHas('messages', [
            'conversation_id' => $conversation->id,
            'sender_type' => 'human',
            'body' => 'Hello on WhatsApp',
            'provider' => 'whatsapp',
            'provider_message_id' => 'wamid-out-1',
            'delivery_status' => 'sent',
        ]);
    }

    private function organizationWithAnswer(): Organization
    {
        $organization = Organization::factory()->create();
        $intent = Intent::factory()->create([
            'organization_id' => $organization->id,
            'confidence_threshold' => 0.7000,
        ]);

        IntentPhrase::factory()->create([
            'organization_id' => $organization->id,
            'intent_id' => $intent->id,
            'phrase' => 'delivery charge koto',
        ]);

        ResponseTemplate::factory()->create([
            'organization_id' => $organization->id,
            'intent_id' => $intent->id,
            'body' => 'Dhakar vitore delivery charge 80 taka.',
        ]);

        return $organization;
    }

    /**
     * @return array{0: User, 1: Organization, 2: Conversation}
     */
    private function externalConversation(string $channel, string $externalId): array
    {
        $user = User::factory()->create();
        $organization = Organization::factory()->create();
        $contact = Contact::factory()->create([
            'organization_id' => $organization->id,
            'channel' => $channel,
            'external_id' => $externalId,
        ]);
        $conversation = Conversation::factory()->create([
            'organization_id' => $organization->id,
            'contact_id' => $contact->id,
            'channel' => $channel,
        ]);

        Membership::factory()->create([
            'organization_id' => $organization->id,
            'user_id' => $user->id,
            'role' => 'owner',
        ]);

        return [$user, $organization, $conversation];
    }
}
