<?php

namespace Tests\Feature;

use App\Models\Central\Company;
use App\Models\Central\Plan;
use App\Models\Tenant\Client;
use App\Models\Tenant\ServiceReminderSent;
use App\Models\Tenant\Vehicle;
use App\Models\Tenant\WorkOrder;
use App\Services\NotificationDispatcher;
use App\Tenancy\TenantManager;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;

class TelegramNotificationsTest extends TestCase
{
    use RefreshDatabase;

    public function test_webhook_links_client_via_shared_phone(): void
    {
        $ctx = $this->makeContext(withBot: true);

        $payload = [
            'message' => [
                'chat' => ['id' => '555111222'],
                'contact' => ['phone_number' => $ctx['client']->phone],
                'text' => '',
            ],
        ];

        Http::fake(['*' => Http::response(['ok' => true])]);

        $resp = $this->withHeaders([
            'X-Telegram-Bot-Api-Secret-Token' => 'secret-' . $ctx['company']->slug,
        ])->postJson("/telegram/webhook/{$ctx['company']->slug}", $payload);

        $resp->assertOk();
        $ctx['client']->refresh();
        $this->assertEquals('555111222', $ctx['client']->telegram_chat_id);
    }

    public function test_webhook_rejects_wrong_secret(): void
    {
        $ctx = $this->makeContext(withBot: true);

        $resp = $this->withHeaders(['X-Telegram-Bot-Api-Secret-Token' => 'wrong'])
            ->postJson("/telegram/webhook/{$ctx['company']->slug}", ['message' => []]);

        $resp->assertStatus(401);
    }

    public function test_dispatcher_uses_telegram_when_chat_id_present(): void
    {
        $ctx = $this->makeContext(withBot: true);
        $ctx['client']->telegram_chat_id = '999';
        $ctx['client']->saveQuietly();

        Http::fake([
            'api.telegram.org/*' => Http::response(['ok' => true, 'result' => []]),
        ]);

        $wo = $this->makeWorkOrder($ctx);
        $ok = app(NotificationDispatcher::class)->workOrderReady($wo);

        $this->assertTrue($ok);
        Http::assertSent(fn ($req) => str_contains($req->url(), 'sendMessage'));
    }

    public function test_dispatcher_falls_back_to_email_when_no_chat_id(): void
    {
        $ctx = $this->makeContext(withBot: true);
        // No chat_id set on client.
        \Illuminate\Support\Facades\Mail::fake();

        Http::fake();

        $wo = $this->makeWorkOrder($ctx);
        $ok = app(NotificationDispatcher::class)->workOrderReady($wo);

        $this->assertTrue($ok);
        Http::assertNothingSent();
        \Illuminate\Support\Facades\Mail::assertSent(\App\Mail\WorkOrderReadyMail::class);
    }

    public function test_dispatcher_returns_false_when_all_channels_disabled(): void
    {
        $ctx = $this->makeContext(withBot: true);
        $ctx['client']->email = null;
        $ctx['client']->saveQuietly();

        $wo = $this->makeWorkOrder($ctx);
        $ok = app(NotificationDispatcher::class)->workOrderReady($wo);
        $this->assertFalse($ok);
    }

    public function test_reminder_cron_respects_cooldown(): void
    {
        $ctx = $this->makeContext();

        // Set settings: after_days=1 (anything older than 1 day triggers)
        $ctx['company']->update(['settings' => array_merge((array) $ctx['company']->settings, [
            'reminder' => ['after_days' => 1, 'cooldown_days' => 30],
        ])]);

        $client = $ctx['client'];
        $vehicle = Vehicle::create([
            'client_id' => $client->id,
            'make' => 'BMW', 'model' => 'X5',
            'plate' => 'REM-1',
        ]);

        // Closed WO 5 days ago.
        WorkOrder::create([
            'number' => WorkOrder::generateNumber($ctx['company']->id),
            'client_id' => $client->id,
            'vehicle_id' => $vehicle->id,
            'opened_at' => now()->subDays(10),
            'closed_at' => now()->subDays(5),
            'status' => 'done',
        ]);

        // Already sent within cooldown.
        ServiceReminderSent::create([
            'company_id' => $ctx['company']->id,
            'vehicle_id' => $vehicle->id,
            'client_id' => $client->id,
            'channel' => 'email',
            'type' => 'general',
            'sent_at' => now()->subDays(5),
        ]);

        \Illuminate\Support\Facades\Mail::fake();

        $this->artisan('reminders:send', ['--slug' => $ctx['company']->slug])
            ->assertSuccessful();

        \Illuminate\Support\Facades\Mail::assertNothingSent();
    }

    private function makeContext(bool $withBot = false): array
    {
        $plan = Plan::firstOrCreate(['slug' => 'test'], [
            'name' => 'Test', 'price' => 0, 'features' => [],
        ]);
        $slug = 'tg-' . uniqid();
        $settings = [];
        if ($withBot) {
            $settings['telegram'] = [
                'bot_token' => 'FAKE:TOKEN',
                'webhook_secret' => "secret-{$slug}",
            ];
        }
        $company = Company::create([
            'plan_id' => $plan->id,
            'slug' => $slug,
            'name' => 'TG Service',
            'status' => 'active',
            'settings' => $settings,
        ]);
        app(TenantManager::class)->setCurrent($company);

        $client = Client::create([
            'name' => 'Tester',
            'phone' => '+37377' . random_int(100000, 999999),
            'email' => 'tester@example.com',
            'type' => 'individual',
            'status' => 'active',
        ]);

        return compact('company', 'client');
    }

    private function makeWorkOrder(array $ctx): WorkOrder
    {
        $vehicle = Vehicle::create([
            'client_id' => $ctx['client']->id,
            'make' => 'Audi', 'model' => 'A4',
            'plate' => 'TG-' . random_int(100, 999),
        ]);
        $wo = WorkOrder::create([
            'number' => WorkOrder::generateNumber($ctx['company']->id),
            'client_id' => $ctx['client']->id,
            'vehicle_id' => $vehicle->id,
            'opened_at' => now(),
            'status' => 'ready',
            'total' => 250.00,
        ]);
        return $wo;
    }
}
