<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Models\BalanceTransaction;
use App\Models\PricingTier;
use App\Models\Tenant;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

/**
 * Идемпотентная одноразовая миграция: balance_leads → balance_rub по цене ступени 1.
 *
 * Запускается ОДИН РАЗ в проде после деплоя Billing v2 Spec A Phase A. Повторный
 * запуск — no-op (тенанты с balance_leads=0 уже не обрабатываются).
 *
 * Per-tenant атомарность: lockForUpdate(Tenant) внутри DB::transaction.
 *
 * Spec: docs/superpowers/specs/2026-05-23-billing-v2-spec-a-balance-rub-design.md §4.4
 * Plan: docs/superpowers/plans/2026-05-23-billing-v2-spec-a-balance-rub-plan.md Task A.11
 */
final class BillingMigrateLeadsToRubCommand extends Command
{
    protected $signature = 'billing:migrate-leads-to-rub';

    protected $description = 'Convert legacy balance_leads to balance_rub at tier 1 price (idempotent, run once in prod)';

    public function handle(): int
    {
        $tier1 = PricingTier::query()
            ->where('is_active', true)
            ->where('tier_no', 1)
            ->where('effective_from', '<=', Carbon::now('Europe/Moscow')->toDateString())
            ->orderBy('effective_from', 'desc')
            ->first();

        if ($tier1 === null) {
            $this->error('No active tier 1 found. Aborting.');

            return self::FAILURE;
        }

        $count = 0;

        Tenant::query()
            ->where('balance_leads', '>', 0)
            ->chunkById(100, function ($tenants) use ($tier1, &$count): void {
                foreach ($tenants as $tenant) {
                    DB::transaction(function () use ($tenant, $tier1, &$count): void {
                        /** @var Tenant|null $locked */
                        $locked = Tenant::query()
                            ->whereKey($tenant->id)
                            ->lockForUpdate()
                            ->first();

                        if ($locked === null || (int) $locked->balance_leads <= 0) {
                            return;  // idempotency — already migrated or zero
                        }

                        $migratedLeads = (int) $locked->balance_leads;
                        $migratedKopecks = bcmul((string) $migratedLeads, (string) $tier1->price_per_lead_kopecks, 0);
                        $migratedRub = bcdiv((string) $migratedKopecks, '100', 2);
                        $newBalanceRub = bcadd((string) $locked->balance_rub, $migratedRub, 2);

                        DB::table('tenants')
                            ->where('id', $locked->id)
                            ->update([
                                'balance_rub' => $newBalanceRub,
                                'balance_leads' => 0,
                            ]);

                        BalanceTransaction::create([
                            'tenant_id' => $locked->id,
                            'type' => BalanceTransaction::TYPE_MIGRATION,
                            'amount_leads' => -$migratedLeads,
                            'amount_rub' => $migratedRub,
                            'balance_leads_after' => 0,
                            'balance_rub_after' => $newBalanceRub,
                            'description' => 'Конвертация предоплаченных лидов в ₽ (миграция модели биллинга Spec A)',
                            'created_at' => now(),
                        ]);

                        $count++;
                    });
                }
            });

        $this->info("Migrated {$count} tenant(s).");

        return self::SUCCESS;
    }
}
