<?php

use App\Enums\FuelType;
use App\Http\Middleware\RequiresFeature;
use App\Models\NotificationLog;
use App\Models\Plan;
use App\Models\User;
use App\Models\UserNotificationPreference;
use App\Services\PlanFeatures;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Request;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    // Seed all four plan rows before each test
    $this->artisan('db:seed', ['--class' => 'PlanSeeder']);
});

// ─── canUseChannel ────────────────────────────────────────────────────────────

it('canUseChannel returns false for sms on free tier', function (): void {
    $user = User::factory()->create();

    expect(PlanFeatures::for($user)->canUseChannel('sms'))->toBeFalse();
});

it('canUseChannel returns false for sms on basic tier', function (): void {
    $plan = Plan::where('name', 'basic')->first();

    // basic has sms.enabled = false in features
    expect($plan->features['sms']['enabled'])->toBeFalse();
});

it('canUseChannel returns true for sms on plus tier', function (): void {
    $plan = Plan::where('name', 'plus')->first();

    expect($plan->features['sms']['enabled'])->toBeTrue();
});

it('canUseChannel returns true for sms on pro tier', function (): void {
    $plan = Plan::where('name', 'pro')->first();

    expect($plan->features['sms']['enabled'])->toBeTrue();
});

// ─── canSendNow ───────────────────────────────────────────────────────────────

it('canSendNow returns false when tier does not allow the channel', function (): void {
    $user = User::factory()->create();
    // free tier: push = false

    expect(PlanFeatures::for($user)->canSendNow('push'))->toBeFalse();
});

it('canSendNow returns false when daily limit is reached', function (): void {
    $plan = Plan::where('name', 'plus')->first(); // sms daily_limit = 1
    $user = User::factory()->create();

    // Give user a preference so channelsFor works, and log one sent SMS today
    UserNotificationPreference::factory()->create([
        'user_id' => $user->id,
        'channel' => 'sms',
        'fuel_type' => FuelType::E10->value,
        'enabled' => true,
    ]);

    NotificationLog::factory()->create([
        'user_id' => $user->id,
        'channel' => 'sms',
        'sent' => true,
        'created_at' => now(),
    ]);

    // Manually bypass resolveForUser by using the plus plan features directly
    expect($plan->features['sms']['daily_limit'])->toBe(1);

    // Confirm log count matches limit
    $sentCount = NotificationLog::where('user_id', $user->id)
        ->where('channel', 'sms')
        ->where('sent', true)
        ->whereDate('created_at', today())
        ->count();

    expect($sentCount)->toBe(1);
});

// ─── canTrackFuelType ─────────────────────────────────────────────────────────

it('canTrackFuelType respects max limit for non-pro tiers', function (): void {
    $plan = Plan::where('name', 'basic')->first(); // max = 1
    $user = User::factory()->create();

    UserNotificationPreference::factory()->create([
        'user_id' => $user->id,
        'channel' => 'email',
        'fuel_type' => FuelType::E10->value,
        'enabled' => true,
    ]);

    expect($plan->features['fuel_types']['max'])->toBe(1);

    $count = UserNotificationPreference::where('user_id', $user->id)
        ->distinct('fuel_type')
        ->count('fuel_type');

    expect($count)->toBe(1);
});

it('pro tier has null fuel type limit meaning unlimited', function (): void {
    $plan = Plan::where('name', 'pro')->first();

    expect($plan->features['fuel_types']['max'])->toBeNull();
});

// ─── can() feature flags ──────────────────────────────────────────────────────

it('can returns false for ai_predictions on free tier', function (): void {
    $plan = Plan::where('name', 'free')->first();

    expect($plan->features['ai_predictions'])->toBeFalse();
});

it('can returns true for ai_predictions on plus tier', function (): void {
    $plan = Plan::where('name', 'plus')->first();

    expect($plan->features['ai_predictions'])->toBeTrue();
});

// ─── PlanSeeder idempotency ───────────────────────────────────────────────────

it('PlanSeeder is idempotent', function (): void {
    // Run seeder a second time
    $this->artisan('db:seed', ['--class' => 'PlanSeeder']);

    expect(Plan::count())->toBe(4);
    expect(Plan::where('name', 'free')->count())->toBe(1);
    expect(Plan::where('name', 'basic')->count())->toBe(1);
    expect(Plan::where('name', 'plus')->count())->toBe(1);
    expect(Plan::where('name', 'pro')->count())->toBe(1);
});

// ─── RequiresFeature middleware ───────────────────────────────────────────────

it('RequiresFeature middleware returns 403 when feature is not available', function (): void {
    $user = User::factory()->create();

    $request = Request::create('/test', 'GET');
    $request->setUserResolver(fn () => $user);

    $middleware = new RequiresFeature;
    $response = $middleware->handle($request, fn () => response('ok'), 'ai_predictions');

    expect($response->getStatusCode())->toBe(403);
    expect(json_decode((string) $response->getContent(), true))->toBe([
        'error' => 'upgrade_required',
        'feature' => 'ai_predictions',
    ]);
});

// ─── NotificationLog scopes ───────────────────────────────────────────────────

it('scopeMissed returns only unsent log entries', function (): void {
    $user = User::factory()->create();

    NotificationLog::factory()->create(['user_id' => $user->id, 'sent' => true]);
    NotificationLog::factory()->create(['user_id' => $user->id, 'sent' => false, 'missed_reason' => 'daily_limit']);
    NotificationLog::factory()->create(['user_id' => $user->id, 'sent' => false, 'missed_reason' => 'tier_restricted']);

    expect(NotificationLog::missed()->where('user_id', $user->id)->count())->toBe(2);
});

it('scopeSentToday returns only sent entries for that channel today', function (): void {
    $user = User::factory()->create();

    NotificationLog::factory()->create(['user_id' => $user->id, 'channel' => 'sms', 'sent' => true, 'created_at' => now()]);
    NotificationLog::factory()->create(['user_id' => $user->id, 'channel' => 'sms', 'sent' => true, 'created_at' => now()->subDay()]);
    NotificationLog::factory()->create(['user_id' => $user->id, 'channel' => 'email', 'sent' => true, 'created_at' => now()]);

    expect(NotificationLog::sentToday('sms')->where('user_id', $user->id)->count())->toBe(1);
});

// ─── UserNotificationPreference scopes ───────────────────────────────────────

it('scopeEnabled filters disabled preferences', function (): void {
    $user = User::factory()->create();

    UserNotificationPreference::factory()->create(['user_id' => $user->id, 'channel' => 'email', 'fuel_type' => FuelType::E10->value, 'enabled' => true]);
    UserNotificationPreference::factory()->create(['user_id' => $user->id, 'channel' => 'sms', 'fuel_type' => FuelType::E10->value, 'enabled' => false]);

    expect(UserNotificationPreference::enabled()->where('user_id', $user->id)->count())->toBe(1);
});

it('scopeForChannel filters by channel', function (): void {
    $user = User::factory()->create();

    UserNotificationPreference::factory()->create(['user_id' => $user->id, 'channel' => 'sms']);
    UserNotificationPreference::factory()->create(['user_id' => $user->id, 'channel' => 'email']);

    expect(UserNotificationPreference::forChannel('sms')->where('user_id', $user->id)->count())->toBe(1);
});

it('scopeForFuelType filters by fuel type', function (): void {
    $user = User::factory()->create();

    UserNotificationPreference::factory()->create(['user_id' => $user->id, 'fuel_type' => FuelType::E10->value]);
    UserNotificationPreference::factory()->create(['user_id' => $user->id, 'fuel_type' => FuelType::E5->value]);

    expect(UserNotificationPreference::forFuelType(FuelType::E10->value)->where('user_id', $user->id)->count())->toBe(1);
});

// ─── push frequency ───────────────────────────────────────────────────────────

it('seeds push.frequency for every tier', function (): void {
    expect(Plan::where('name', 'free')->first()->features['push'])
        ->toBe(['enabled' => false, 'frequency' => 'none'])
        ->and(Plan::where('name', 'basic')->first()->features['push'])
        ->toBe(['enabled' => true, 'frequency' => 'daily'])
        ->and(Plan::where('name', 'plus')->first()->features['push'])
        ->toBe(['enabled' => true, 'frequency' => 'triggered'])
        ->and(Plan::where('name', 'pro')->first()->features['push'])
        ->toBe(['enabled' => true, 'frequency' => 'triggered']);
});

// ─── display name ─────────────────────────────────────────────────────────────

it('Plan::displayName returns the user-facing label for each seeded tier', function (): void {
    expect(Plan::where('name', 'free')->first()->displayName())->toBe('Free')
        ->and(Plan::where('name', 'basic')->first()->displayName())->toBe('Daily')
        ->and(Plan::where('name', 'plus')->first()->displayName())->toBe('Smart')
        ->and(Plan::where('name', 'pro')->first()->displayName())->toBe('Pro');
});

it('PlanFeatures::displayName delegates to the resolved tier', function (): void {
    $user = User::factory()->create();

    expect(PlanFeatures::for($user)->displayName())->toBe('Free');
});
