<?php

declare(strict_types=1);

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

/**
 * Создаёт ежемесячные партиции для `deals` и `supplier_lead_costs`
 * на N месяцев вперёд от текущей даты.
 *
 * Замена `pg_partman` на native Windows-стеке (расширение недоступно
 * без сборки из исходников). Запускается ежесуточно через Windows Task
 * Scheduler / cron — идемпотентна (CREATE TABLE IF NOT EXISTS).
 *
 * По дефолту 2 месяца вперёд (паритет с инициализацией schema.sql:
 * 6 партиций при `migrate:fresh`, последующие месяцы — этим cron'ом).
 *
 * Источник: db/schema.sql §5 (deals partition), §8.5 (supplier_lead_costs);
 * project_phase1_strategy.md (pg_partman заменён ручным cron'ом).
 */
class PartitionsCreateMonths extends Command
{
    /** @var string */
    protected $signature = 'partitions:create-months {--ahead=2 : Сколько месяцев вперёд создать партиций}';

    /** @var string */
    protected $description = 'Создаёт ежемесячные партиции deals и supplier_lead_costs на N месяцев вперёд (idempotent)';

    /**
     * Список таблиц, которые партиционируются по received_at помесячно.
     *
     * @var array<int, string>
     */
    private const PARTITIONED_TABLES = ['deals', 'supplier_lead_costs'];

    public function handle(): int
    {
        $ahead = max(1, (int) $this->option('ahead'));
        $now = Carbon::now()->startOfMonth();

        $created = 0;
        $skipped = 0;

        for ($i = 0; $i <= $ahead; $i++) {
            $monthStart = $now->copy()->addMonths($i);
            $monthEnd = $monthStart->copy()->addMonth();

            foreach (self::PARTITIONED_TABLES as $table) {
                $partitionName = sprintf('%s_%s', $table, $monthStart->format('Y_m'));

                if ($this->partitionExists($partitionName)) {
                    $skipped++;
                    $this->line("  skip   <fg=gray>{$partitionName}</> (already exists)");

                    continue;
                }

                DB::statement(sprintf(
                    "CREATE TABLE %s PARTITION OF %s FOR VALUES FROM ('%s') TO ('%s')",
                    $partitionName,
                    $table,
                    $monthStart->format('Y-m-d'),
                    $monthEnd->format('Y-m-d'),
                ));
                $created++;
                $this->info("  create <fg=green>{$partitionName}</> [{$monthStart->format('Y-m-d')} → {$monthEnd->format('Y-m-d')})");
            }
        }

        $this->newLine();
        $this->info("Done: {$created} created, {$skipped} skipped (ahead={$ahead}).");

        return self::SUCCESS;
    }

    /**
     * Проверка существования партиции через pg_class (быстрее information_schema).
     */
    private function partitionExists(string $name): bool
    {
        $row = DB::selectOne(
            "SELECT 1 AS exists FROM pg_class WHERE relname = ? AND relkind = 'r'",
            [$name],
        );

        return $row !== null;
    }
}
