<?php

declare(strict_types=1);

use App\Models\Project;
use App\Models\Tenant;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

uses(DatabaseTransactions::class);

beforeEach(function () {
    $this->tenant = Tenant::factory()->create([
        'subdomain' => 'okna-moscow',
        'organization_name' => 'Окна Москва ООО',
        'contact_email' => 'admin@okna-moscow.ru',
        'is_trial' => false,
        'balance_rub' => 14250.00,
        'balance_leads' => 5,
    ]);
});

test('GET /api/admin/tenants/{subdomain}: 404 unknown', function () {
    $this->getJson('/api/admin/tenants/unknown-subdomain')->assertStatus(404);
});

test('GET /api/admin/tenants/{subdomain}: 404 для soft-deleted', function () {
    DB::table('tenants')->where('id', $this->tenant->id)->update(['deleted_at' => Carbon::now()]);
    $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}")->assertStatus(404);
});

test('GET /api/admin/tenants/{subdomain}: возвращает базовые поля', function () {
    $response = $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}");
    $response->assertOk();
    expect($response->json('tenant.subdomain'))->toBe('okna-moscow');
    expect($response->json('tenant.organization_name'))->toBe('Окна Москва ООО');
    expect($response->json('tenant.contact_email'))->toBe('admin@okna-moscow.ru');
    expect($response->json('tenant.balance_rub'))->toBe('14250.00');
    expect($response->json('tenant.balance_leads'))->toBe(5);
    expect($response->json('tenant.is_trial'))->toBeFalse();
});

test('GET /api/admin/tenants/{subdomain}: response содержит 4 секции + metrics', function () {
    $response = $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}");
    $response->assertOk();
    expect($response->json())->toHaveKey('users');
    expect($response->json())->toHaveKey('projects');
    expect($response->json())->toHaveKey('balance_history');
    expect($response->json())->toHaveKey('activity');
    expect($response->json())->toHaveKey('metrics');
    expect($response->json('metrics'))->toHaveKey('leads_today');
    expect($response->json('metrics'))->toHaveKey('avg_lead_cost_rub');
    expect($response->json('metrics'))->toHaveKey('runway_days');
});

test('GET show: users возвращает свои + изоляция от чужих', function () {
    User::factory()->create(['tenant_id' => $this->tenant->id, 'email' => 'mine@test.io']);
    $other = Tenant::factory()->create(['subdomain' => 'other-co']);
    User::factory()->create(['tenant_id' => $other->id, 'email' => 'foreign@test.io']);

    $response = $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}");
    $emails = array_column($response->json('users'), 'email');
    expect($emails)->toContain('mine@test.io');
    expect($emails)->not->toContain('foreign@test.io');
});

test('GET show: projects возвращает с suppliers_count + leads_today', function () {
    $project = Project::factory()->create([
        'tenant_id' => $this->tenant->id,
        'name' => 'Натяжные потолки',
        'tag' => 'natyazhnye-potolki',
        'is_active' => true,
    ]);

    // suppliers — глобальная таблица (без tenant_id), code UNIQUE.
    $supplierIds = [];
    foreach (range(1, 2) as $i) {
        $supplierIds[] = DB::table('suppliers')->insertGetId([
            'code' => 'b'.Str::random(6),
            'name' => "Supplier {$i}",
            'accepts_types' => '{websites}',
            'cost_rub' => 100.00,
            'channel' => 'sites',
            'created_at' => Carbon::now(),
            'updated_at' => Carbon::now(),
        ]);
    }
    foreach ($supplierIds as $sid) {
        DB::table('project_suppliers')->insert([
            'project_id' => $project->id,
            'supplier_id' => $sid,
            'is_active' => true,
            'created_at' => Carbon::now(),
            'updated_at' => Carbon::now(),
        ]);
    }

    // 2 deals сегодня для проекта (используем сегодняшний день — партиция точно есть).
    foreach (range(1, 2) as $i) {
        DB::table('deals')->insert([
            'tenant_id' => $this->tenant->id,
            'project_id' => $project->id,
            'phone' => "+7999000000{$i}",
            'status' => 'new',
            'received_at' => Carbon::now(),
            'created_at' => Carbon::now(),
            'updated_at' => Carbon::now(),
        ]);
    }

    $response = $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}");
    $projects = $response->json('projects');
    expect($projects)->toHaveCount(1);
    expect($projects[0]['name'])->toBe('Натяжные потолки');
    expect($projects[0]['suppliers_count'])->toBe(2);
    expect($projects[0]['leads_today'])->toBe(2);
});

test('GET show: balance_history возвращает свои tx + ORDER created_at DESC + LIMIT 30', function () {
    foreach (range(1, 35) as $i) {
        DB::table('balance_transactions')->insert([
            'tenant_id' => $this->tenant->id,
            'type' => $i % 3 === 0 ? 'topup' : 'lead_charge',
            'amount_rub' => $i % 3 === 0 ? 1000 : -200,
            'created_at' => Carbon::now()->subMinutes(35 - $i),
        ]);
    }

    $response = $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}");
    $history = $response->json('balance_history');
    expect($history)->toHaveCount(30);  // LIMIT
    // Самая свежая первая (created_at DESC).
    expect($history[0]['type'])->toBeIn(['topup', 'lead_charge']);
});

test('GET show: balance_history изоляция (чужие tx не показываются)', function () {
    DB::table('balance_transactions')->insert([
        'tenant_id' => $this->tenant->id,
        'type' => 'topup',
        'amount_rub' => 999,
        'description' => 'mine',
        'created_at' => Carbon::now(),
    ]);
    $other = Tenant::factory()->create();
    DB::table('balance_transactions')->insert([
        'tenant_id' => $other->id,
        'type' => 'topup',
        'amount_rub' => 555,
        'description' => 'foreign',
        'created_at' => Carbon::now(),
    ]);

    $response = $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}");
    $descriptions = array_column($response->json('balance_history'), 'description');
    expect($descriptions)->toContain('mine');
    expect($descriptions)->not->toContain('foreign');
});

test('GET show: activity возвращает с actor_email из users LEFT JOIN', function () {
    $user = User::factory()->create(['tenant_id' => $this->tenant->id, 'email' => 'actor@test.io']);
    DB::table('activity_log')->insert([
        'tenant_id' => $this->tenant->id,
        'user_id' => $user->id,
        'deal_id' => 999,
        'event' => 'deal.status_changed',
        'context' => json_encode(['from' => 'new', 'to' => 'in_progress']),
        'created_at' => Carbon::now(),
    ]);
    DB::table('activity_log')->insert([
        'tenant_id' => $this->tenant->id,
        'user_id' => null,  // системное событие
        'deal_id' => 1000,
        'event' => 'webhook.received',
        'created_at' => Carbon::now()->subMinute(),
    ]);

    $response = $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}");
    $activity = $response->json('activity');
    expect($activity)->toHaveCount(2);
    $events = array_column($activity, 'event');
    expect($events)->toContain('deal.status_changed');
    expect($events)->toContain('webhook.received');
    // Самая свежая первая.
    expect($activity[0]['event'])->toBe('deal.status_changed');
    expect($activity[0]['actor_email'])->toBe('actor@test.io');
    expect($activity[1]['actor_email'])->toBeNull();
});

test('GET show: metrics.leads_today + this_week + this_month', function () {
    $project = Project::factory()->create(['tenant_id' => $this->tenant->id]);

    // 1 deal сегодня
    DB::table('deals')->insert([
        'tenant_id' => $this->tenant->id,
        'project_id' => $project->id,
        'phone' => '+79991111111',
        'status' => 'new',
        'received_at' => Carbon::now(),
        'created_at' => Carbon::now(),
        'updated_at' => Carbon::now(),
    ]);

    $response = $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}");
    expect($response->json('metrics.leads_today'))->toBe(1);
    expect($response->json('metrics.leads_this_week'))->toBeGreaterThanOrEqual(1);
    expect($response->json('metrics.leads_this_month'))->toBeGreaterThanOrEqual(1);
});

test('GET show: metrics.runway_days computed из baalance + spend', function () {
    // 30000 ₽ списано за 30 дней → avg_daily = 1000.
    // Баланс 14250 → runway ~ 14 дней.
    DB::table('balance_transactions')->insert([
        'tenant_id' => $this->tenant->id,
        'type' => 'lead_charge',
        'amount_rub' => -30000,
        'created_at' => Carbon::now()->subDays(15),
    ]);

    $response = $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}");
    $runway = $response->json('metrics.runway_days');
    expect($runway)->toBeGreaterThan(10);
    expect($runway)->toBeLessThan(20);
});

test('GET show: tariff_name + mrr_rub когда есть current_tariff_id', function () {
    $tariffId = DB::table('tariff_plans')->insertGetId([
        'code' => 'team-'.Str::random(6),
        'name' => 'Команда',
        'billing_model' => 'monthly',
        'price_monthly' => 990.00,
        'is_active' => true,
        'created_at' => Carbon::now(),
        'updated_at' => Carbon::now(),
    ]);
    DB::table('tenants')->where('id', $this->tenant->id)->update(['current_tariff_id' => $tariffId]);

    $response = $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}");
    expect($response->json('tenant.tariff_name'))->toBe('Команда');
    expect($response->json('tenant.mrr_rub'))->toBe('990.00');
});

test('GET show: mrr_rub null для trial-тенанта (даже если есть тариф)', function () {
    $tariffId = DB::table('tariff_plans')->insertGetId([
        'code' => 'team-tr-'.Str::random(6),
        'name' => 'Команда',
        'billing_model' => 'monthly',
        'price_monthly' => 990.00,
        'is_active' => true,
        'created_at' => Carbon::now(),
        'updated_at' => Carbon::now(),
    ]);
    DB::table('tenants')->where('id', $this->tenant->id)->update([
        'is_trial' => true,
        'current_tariff_id' => $tariffId,
    ]);

    $response = $this->getJson("/api/admin/tenants/{$this->tenant->subdomain}");
    expect($response->json('tenant.is_trial'))->toBeTrue();
    expect($response->json('tenant.mrr_rub'))->toBeNull();
});
