<?php

declare(strict_types=1);

use App\Models\PricingTier;
use App\Services\Billing\BalanceToLeadsConverter;
use Illuminate\Database\Eloquent\Collection;

function buildTier(int $no, ?int $cap, int $priceKopecks): PricingTier
{
    $t = new PricingTier;
    $t->tier_no = $no;
    $t->leads_in_tier = $cap;
    $t->price_per_lead_kopecks = $priceKopecks;
    $t->is_active = true;

    return $t;
}

beforeEach(function () {
    $this->tiers = new Collection([
        buildTier(1, 50, 12000),
        buildTier(2, 100, 10000),
        buildTier(3, 200, 8000),
        buildTier(7, null, 6000),
    ]);
});

it('returns 0 leads when balance is zero', function () {
    $result = (new BalanceToLeadsConverter)->convert('0.00', 0, $this->tiers);
    expect($result['leads'])->toBe(0);
});

it('takes only tier 1 when balance covers only first tier', function () {
    $result = (new BalanceToLeadsConverter)->convert('1200.00', 0, $this->tiers);
    expect($result['leads'])->toBe(10);
    expect($result['breakdown'])->toHaveCount(1);
    expect($result['breakdown'][0]['tier_no'])->toBe(1);
    expect($result['breakdown'][0]['leads'])->toBe(10);
});

it('crosses tier 1 → tier 2 with deliveredInMonth=30', function () {
    // 30 already delivered, 5000 ₽ remaining
    // tier 1 has 20 slots × 120₽ = 2400 ₽ → 20 leads, balance = 2600 ₽
    // tier 2 has 100 slots, 2600/100 = 26 leads → 26 leads
    // total = 46
    $result = (new BalanceToLeadsConverter)->convert('5000.00', 30, $this->tiers);
    expect($result['leads'])->toBe(46);
    expect($result['breakdown'])->toHaveCount(2);
    expect($result['breakdown'][0])->toMatchArray(['tier_no' => 1, 'leads' => 20]);
    expect($result['breakdown'][1])->toMatchArray(['tier_no' => 2, 'leads' => 26]);
    expect($result['current_tier']['no'])->toBe(1);
    expect($result['current_tier']['leads_left_in_tier'])->toBe(20);
    expect($result['next_tier']['no'])->toBe(2);
});

it('skips already-exhausted tier 1 when deliveredInMonth=50', function () {
    $result = (new BalanceToLeadsConverter)->convert('1000.00', 50, $this->tiers);
    // tier 1 exhausted; on tier 2: 1000/100 = 10 leads
    expect($result['leads'])->toBe(10);
    expect($result['current_tier']['no'])->toBe(2);
});

it('uses last tier with leads_in_tier=NULL as catch-all', function () {
    $result = (new BalanceToLeadsConverter)->convert('600.00', 350, $this->tiers);
    // tier 1+2+3 exhausted (350 = 50+100+200). Tier 7: 600/60 = 10 leads.
    expect($result['leads'])->toBe(10);
    expect($result['current_tier']['no'])->toBe(7);
});

it('handles exact-kopeck balance precisely (no float drift)', function () {
    $result = (new BalanceToLeadsConverter)->convert('120.00', 0, $this->tiers);
    expect($result['leads'])->toBe(1);
});

it('returns 0 when balance is less than tier 1 price', function () {
    $result = (new BalanceToLeadsConverter)->convert('119.99', 0, $this->tiers);
    expect($result['leads'])->toBe(0);
});

it('ignores inactive tiers', function () {
    $inactive = buildTier(2, 100, 1);
    $inactive->is_active = false;
    $tiers = new Collection([buildTier(1, 50, 12000), $inactive, buildTier(7, null, 6000)]);
    $result = (new BalanceToLeadsConverter)->convert('5000.00', 50, $tiers);
    // tier 1 exhausted, tier 2 inactive (skipped), tier 7: 5000/60 = 83 leads
    expect($result['leads'])->toBe(83);
});
