<?php
declare(strict_types=1);

use App\Core\Database\ConnectionFactory;
use App\Core\Support\Env;

$basePath = dirname(__DIR__);
$vendorAutoload = $basePath . '/vendor/autoload.php';

if (is_file($vendorAutoload)) {
    require $vendorAutoload;
} else {
    spl_autoload_register(static function (string $class) use ($basePath): void {
        $prefix = 'App\\';
        if (!str_starts_with($class, $prefix)) {
            return;
        }
        $relative = substr($class, strlen($prefix));
        $file = $basePath . '/src/' . str_replace('\\', '/', $relative) . '.php';
        if (is_file($file)) {
            require $file;
        }
    });
}

Env::load($basePath . '/.env');

/** @var array<string, mixed> $dbConfig */
$dbConfig = require $basePath . '/config/database.php';

$args = $argv;
array_shift($args);
$useRemote = in_array('--use-remote', $args, true);
$append = in_array('--append', $args, true);
$count = 30;
$profile = 'default';
foreach ($args as $arg) {
    if (str_starts_with($arg, '--count=')) {
        $count = max(1, min(500, (int) substr($arg, 8)));
    }
    if (str_starts_with($arg, '--profile=')) {
        $parsedProfile = strtolower(trim((string) substr($arg, 10)));
        if (in_array($parsedProfile, ['default', 'realistic'], true)) {
            $profile = $parsedProfile;
        }
    }
}

if ($useRemote) {
    $remoteHost = (string) Env::get('DB_HOST_REMOTE', '');
    if ($remoteHost !== '') {
        $dbConfig['host'] = $remoteHost;
    }
}

$pdo = ConnectionFactory::make($dbConfig);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

echo 'Deploy + seed orders schema' . PHP_EOL;
echo '[db-host] ' . (string) ($dbConfig['host'] ?? '') . PHP_EOL;
echo '[count] ' . $count . PHP_EOL;
echo '[profile] ' . $profile . PHP_EOL;
echo '[mode] ' . ($append ? 'append' : 'reset+seed') . PHP_EOL;

try {
    deploySchema($pdo, $basePath . '/database/drafts/20260302_orders_schema_v1.sql');
    seedData($pdo, $count, $append, $profile);
    printSummary($pdo);
    echo 'Done.' . PHP_EOL;
} catch (Throwable $exception) {
    fwrite(STDERR, '[error] ' . $exception->getMessage() . PHP_EOL);
    exit(1);
}

function deploySchema(PDO $pdo, string $sqlFile): void
{
    if (!is_file($sqlFile)) {
        throw new RuntimeException('SQL draft file not found: ' . $sqlFile);
    }
    $rawSql = (string) file_get_contents($sqlFile);
    $withoutLineComments = preg_replace('/^\s*--.*$/m', '', $rawSql) ?? $rawSql;
    $statements = preg_split('/;\s*[\r\n]+/', $withoutLineComments) ?: [];
    foreach ($statements as $statement) {
        $sql = trim($statement);
        if ($sql === '') {
            continue;
        }
        $pdo->exec($sql);
    }
    echo '[schema] applied' . PHP_EOL;
}

function seedData(PDO $pdo, int $count, bool $append, string $profile): void
{
    if (!$append) {
        $pdo->exec('SET FOREIGN_KEY_CHECKS = 0');
        foreach ([
            'order_tag_links',
            'order_status_history',
            'order_notes',
            'order_documents',
            'order_shipments',
            'order_payments',
            'order_items',
            'order_addresses',
            'orders',
            'order_tags_dict',
            'integration_order_sync_state',
        ] as $table) {
            $pdo->exec('TRUNCATE TABLE ' . $table);
        }
        $pdo->exec('SET FOREIGN_KEY_CHECKS = 1');
    }

    $now = new DateTimeImmutable('now');
    $statuses = loadStatusesForSeed($pdo);
    $paymentTypes = ['transfer', 'card', 'cod', 'blik', 'cash'];
    $carriers = ['dhl', 'inpost', 'dpd', 'ups', 'gls'];
    $itemTypes = ['product', 'shipment', 'service'];
    $currencies = ['PLN', 'EUR', 'USD'];
    $sources = ['shop', 'marketplace', 'api'];
    $noteTypes = ['customer_message', 'internal_note'];
    $tags = ['priority', 'fraud-check', 'gift', 'invoice', 'vip', 'return-risk', 'express'];

    $insertTag = $pdo->prepare(
        'INSERT INTO order_tags_dict (integration_id, source_tag_id, tag_name, is_active, updated_at_external, payload_json, created_at, updated_at)
         VALUES (:integration_id, :source_tag_id, :tag_name, :is_active, :updated_at_external, :payload_json, :created_at, :updated_at)'
    );
    foreach ($tags as $idx => $tagName) {
        $insertTag->execute([
            'integration_id' => random_int(1, 3),
            'source_tag_id' => 'tag_' . ($idx + 1),
            'tag_name' => $tagName,
            'is_active' => 1,
            'updated_at_external' => $now->format('Y-m-d H:i:s'),
            'payload_json' => json_encode(['name' => $tagName], JSON_UNESCAPED_UNICODE),
            'created_at' => $now->format('Y-m-d H:i:s'),
            'updated_at' => $now->format('Y-m-d H:i:s'),
        ]);
    }

    $tagRows = $pdo->query('SELECT id FROM order_tags_dict')->fetchAll(PDO::FETCH_COLUMN);
    $tagIds = array_map(static fn ($id) => (int) $id, is_array($tagRows) ? $tagRows : []);

    $insertOrder = $pdo->prepare(
        'INSERT INTO orders (
            integration_id, source, source_order_id, external_order_id, external_platform_id, external_platform_account_id,
            external_status_id, external_payment_type_id, payment_status, external_carrier_id, external_carrier_account_id,
            customer_login, is_invoice, is_encrypted, is_canceled_by_buyer, currency, total_without_tax, total_with_tax,
            total_paid, send_date_min, send_date_max, ordered_at, source_created_at, source_updated_at, preferences_json,
            payload_json, fetched_at, created_at, updated_at
         ) VALUES (
            :integration_id, :source, :source_order_id, :external_order_id, :external_platform_id, :external_platform_account_id,
            :external_status_id, :external_payment_type_id, :payment_status, :external_carrier_id, :external_carrier_account_id,
            :customer_login, :is_invoice, :is_encrypted, :is_canceled_by_buyer, :currency, :total_without_tax, :total_with_tax,
            :total_paid, :send_date_min, :send_date_max, :ordered_at, :source_created_at, :source_updated_at, :preferences_json,
            :payload_json, :fetched_at, :created_at, :updated_at
         )'
    );

    $insertAddress = $pdo->prepare(
        'INSERT INTO order_addresses (
            order_id, address_type, name, phone, email, street_name, street_number, city, zip_code, country, department,
            parcel_external_id, parcel_name, address_class, company_tax_number, company_name, payload_json, created_at, updated_at
         ) VALUES (
            :order_id, :address_type, :name, :phone, :email, :street_name, :street_number, :city, :zip_code, :country, :department,
            :parcel_external_id, :parcel_name, :address_class, :company_tax_number, :company_name, :payload_json, :created_at, :updated_at
         )'
    );

    $insertItem = $pdo->prepare(
        'INSERT INTO order_items (
            order_id, source_item_id, external_item_id, ean, sku, original_name, original_code, original_price_with_tax,
            original_price_without_tax, media_url, quantity, tax_rate, item_status, unit, item_type, source_product_id,
            source_product_set_id, sort_order, payload_json, created_at, updated_at
         ) VALUES (
            :order_id, :source_item_id, :external_item_id, :ean, :sku, :original_name, :original_code, :original_price_with_tax,
            :original_price_without_tax, :media_url, :quantity, :tax_rate, :item_status, :unit, :item_type, :source_product_id,
            :source_product_set_id, :sort_order, :payload_json, :created_at, :updated_at
         )'
    );

    $insertPayment = $pdo->prepare(
        'INSERT INTO order_payments (
            order_id, source_payment_id, external_payment_id, payment_type_id, payment_date, amount, currency, comment,
            payload_json, created_at, updated_at
         ) VALUES (
            :order_id, :source_payment_id, :external_payment_id, :payment_type_id, :payment_date, :amount, :currency, :comment,
            :payload_json, :created_at, :updated_at
         )'
    );

    $insertShipment = $pdo->prepare(
        'INSERT INTO order_shipments (
            order_id, source_shipment_id, external_shipment_id, tracking_number, carrier_provider_id, posted_at, media_uuid,
            payload_json, created_at, updated_at
         ) VALUES (
            :order_id, :source_shipment_id, :external_shipment_id, :tracking_number, :carrier_provider_id, :posted_at, :media_uuid,
            :payload_json, :created_at, :updated_at
         )'
    );

    $insertDocument = $pdo->prepare(
        'INSERT INTO order_documents (
            order_id, source_document_id, external_document_id, document_number, price_with_tax, price_without_tax, currency,
            currency_value, document_type_id, media_uuid, source_created_at, payload_json, created_at, updated_at
         ) VALUES (
            :order_id, :source_document_id, :external_document_id, :document_number, :price_with_tax, :price_without_tax, :currency,
            :currency_value, :document_type_id, :media_uuid, :source_created_at, :payload_json, :created_at, :updated_at
         )'
    );

    $insertNote = $pdo->prepare(
        'INSERT INTO order_notes (
            order_id, source_note_id, note_type, created_at_external, comment, payload_json, created_at, updated_at
         ) VALUES (
            :order_id, :source_note_id, :note_type, :created_at_external, :comment, :payload_json, :created_at, :updated_at
         )'
    );

    $insertStatusHistory = $pdo->prepare(
        'INSERT INTO order_status_history (
            order_id, from_status_id, to_status_id, changed_at, change_source, comment, payload_json, created_at
         ) VALUES (
            :order_id, :from_status_id, :to_status_id, :changed_at, :change_source, :comment, :payload_json, :created_at
         )'
    );

    $insertTagLink = $pdo->prepare(
        'INSERT INTO order_tag_links (order_id, tag_dict_id, assigned_at, payload_json, created_at)
         VALUES (:order_id, :tag_dict_id, :assigned_at, :payload_json, :created_at)'
    );

    $firstNames = ['Jan', 'Anna', 'Piotr', 'Katarzyna', 'Marek', 'Ewa', 'Tomasz', 'Magda', 'Pawel', 'Karolina'];
    $lastNames = ['Kowalski', 'Nowak', 'Wisniewski', 'Wojcik', 'Kaczmarek', 'Mazur', 'Krawczyk', 'Zielinski'];
    $cities = ['Warszawa', 'Krakow', 'Gdansk', 'Poznan', 'Wroclaw', 'Lodz', 'Lublin', 'Katowice'];

    $pdo->beginTransaction();
    try {
        for ($i = 1; $i <= $count; $i++) {
            $integrationId = random_int(1, 3);
            $source = $sources[array_rand($sources)];
            $currency = $currencies[array_rand($currencies)];
            $status = $statuses[array_rand($statuses)];
            $paymentType = $paymentTypes[array_rand($paymentTypes)];
            $carrier = $carriers[array_rand($carriers)];
            $isInvoice = random_int(0, 1) === 1;
            $orderedAt = $now->sub(new DateInterval('P' . random_int(0, 45) . 'DT' . random_int(0, 23) . 'H'));
            $updatedAt = $orderedAt->add(new DateInterval('PT' . random_int(1, 120) . 'H'));
            $sendMin = $orderedAt->add(new DateInterval('P' . random_int(0, 2) . 'D'));
            $sendMax = $sendMin->add(new DateInterval('P' . random_int(0, 4) . 'D'));

            $totalNet = (float) random_int(5000, 35000) / 100.0;
            $totalGross = round($totalNet * 1.23, 2);
            $paidRatio = [0.0, 0.5, 1.0, 1.1][array_rand([0, 1, 2, 3])];
            $totalPaid = round($totalGross * $paidRatio, 2);
            $paymentStatus = random_int(0, 3);

            if ($profile === 'realistic') {
                $status = weightedChoice([
                    'new' => 10,
                    'confirmed' => 16,
                    'paid' => 18,
                    'processing' => 16,
                    'packed' => 12,
                    'shipped' => 12,
                    'delivered' => 10,
                    'cancelled' => 4,
                    'returned' => 2,
                ]);
                $paymentType = weightedChoice([
                    'transfer' => 30,
                    'card' => 30,
                    'blik' => 22,
                    'cod' => 14,
                    'cash' => 4,
                ]);
                $carrier = weightedChoice([
                    'inpost' => 35,
                    'dhl' => 25,
                    'dpd' => 20,
                    'ups' => 12,
                    'gls' => 8,
                ]);
                $isInvoice = random_int(1, 100) <= 35;
                $orderedAt = $now->sub(new DateInterval('P' . random_int(0, 60) . 'DT' . random_int(0, 23) . 'H'));
                $updatedAt = $orderedAt->add(new DateInterval('PT' . random_int(6, 168) . 'H'));
                $sendMin = $orderedAt->add(new DateInterval('P' . random_int(0, 1) . 'D'));
                $sendMax = $sendMin->add(new DateInterval('P' . random_int(1, 3) . 'D'));
                $totalNet = (float) random_int(6000, 42000) / 100.0;
                $totalGross = round($totalNet * 1.23, 2);

                $statusFinancialRules = [
                    'new' => ['ratio' => [0.0, 0.0, 0.5], 'payment_status' => [0, 0, 1]],
                    'confirmed' => ['ratio' => [0.0, 0.5, 1.0], 'payment_status' => [0, 1, 2]],
                    'paid' => ['ratio' => [1.0, 1.0, 1.0, 0.5], 'payment_status' => [2, 2, 2, 1]],
                    'processing' => ['ratio' => [1.0, 1.0, 1.0], 'payment_status' => [2, 2, 2]],
                    'packed' => ['ratio' => [1.0, 1.0, 1.0], 'payment_status' => [2, 2, 2]],
                    'shipped' => ['ratio' => [1.0, 1.0, 1.0], 'payment_status' => [2, 2, 2]],
                    'delivered' => ['ratio' => [1.0, 1.0, 1.0], 'payment_status' => [2, 2, 2]],
                    'cancelled' => ['ratio' => [0.0, 0.0, 0.5], 'payment_status' => [0, 0, 1]],
                    'returned' => ['ratio' => [1.0, 1.0, 0.0], 'payment_status' => [3, 3, 0]],
                ];
                if (isset($statusFinancialRules[$status])) {
                    $rule = $statusFinancialRules[$status];
                    $paidRatio = (float) $rule['ratio'][array_rand($rule['ratio'])];
                    $paymentStatus = (int) $rule['payment_status'][array_rand($rule['payment_status'])];
                } else {
                    $paidRatio = [0.0, 0.5, 1.0][array_rand([0, 1, 2])];
                    $paymentStatus = [0, 1, 2][array_rand([0, 1, 2])];
                }
                $totalPaid = round($totalGross * $paidRatio, 2);
                if ($status === 'returned' && $paymentStatus === 3) {
                    $totalPaid = 0.00;
                }
            }

            $sourceOrderId = 'ORD-' . $integrationId . '-' . $orderedAt->format('Ymd') . '-' . str_pad((string) $i, 4, '0', STR_PAD_LEFT);
            $externalOrderId = 'EXT-' . random_int(100000, 999999);
            $platformId = 'platform_' . random_int(1, 5);
            $platformAccountId = 'account_' . random_int(1, 8);

            $customerName = $firstNames[array_rand($firstNames)] . ' ' . $lastNames[array_rand($lastNames)];
            $customerEmail = strtolower(str_replace(' ', '.', $customerName)) . random_int(1, 99) . '@example.com';
            $city = $cities[array_rand($cities)];

            $insertOrder->execute([
                'integration_id' => $integrationId,
                'source' => $source,
                'source_order_id' => $sourceOrderId,
                'external_order_id' => $externalOrderId,
                'external_platform_id' => $platformId,
                'external_platform_account_id' => $platformAccountId,
                'external_status_id' => $status,
                'external_payment_type_id' => $paymentType,
                'payment_status' => $paymentStatus,
                'external_carrier_id' => $carrier,
                'external_carrier_account_id' => 'carrier_acc_' . random_int(1, 6),
                'customer_login' => strtolower(str_replace(' ', '.', $customerName)),
                'is_invoice' => $isInvoice ? 1 : 0,
                'is_encrypted' => random_int(0, 1),
                'is_canceled_by_buyer' => $status === 'cancelled' ? 1 : 0,
                'currency' => $currency,
                'total_without_tax' => number_format($totalNet, 2, '.', ''),
                'total_with_tax' => number_format($totalGross, 2, '.', ''),
                'total_paid' => number_format($totalPaid, 2, '.', ''),
                'send_date_min' => $sendMin->format('Y-m-d H:i:s'),
                'send_date_max' => $sendMax->format('Y-m-d H:i:s'),
                'ordered_at' => $orderedAt->format('Y-m-d H:i:s'),
                'source_created_at' => $orderedAt->format('Y-m-d H:i:s'),
                'source_updated_at' => $updatedAt->format('Y-m-d H:i:s'),
                'preferences_json' => json_encode(['gift_wrap' => (bool) random_int(0, 1)], JSON_UNESCAPED_UNICODE),
                'payload_json' => json_encode(['mock' => true, 'v' => 1], JSON_UNESCAPED_UNICODE),
                'fetched_at' => $now->format('Y-m-d H:i:s'),
                'created_at' => $now->format('Y-m-d H:i:s'),
                'updated_at' => $now->format('Y-m-d H:i:s'),
            ]);

            $orderId = (int) $pdo->lastInsertId();

            foreach (['customer', 'delivery'] as $addressType) {
                $insertAddress->execute([
                    'order_id' => $orderId,
                    'address_type' => $addressType,
                    'name' => $customerName,
                    'phone' => '+485' . random_int(10000000, 99999999),
                    'email' => $customerEmail,
                    'street_name' => 'Testowa',
                    'street_number' => (string) random_int(1, 120),
                    'city' => $city,
                    'zip_code' => sprintf('%02d-%03d', random_int(10, 99), random_int(100, 999)),
                    'country' => 'PL',
                    'department' => null,
                    'parcel_external_id' => random_int(0, 3) === 0 ? 'PACZ-' . random_int(1000, 9999) : null,
                    'parcel_name' => null,
                    'address_class' => $isInvoice ? 'company' : 'house',
                    'company_tax_number' => $isInvoice ? 'PL' . random_int(1000000000, 9999999999) : null,
                    'company_name' => $isInvoice ? 'Firma ' . $customerName : null,
                    'payload_json' => json_encode(['type' => $addressType], JSON_UNESCAPED_UNICODE),
                    'created_at' => $now->format('Y-m-d H:i:s'),
                    'updated_at' => $now->format('Y-m-d H:i:s'),
                ]);
            }

            if ($isInvoice) {
                $insertAddress->execute([
                    'order_id' => $orderId,
                    'address_type' => 'invoice',
                    'name' => $customerName,
                    'phone' => '+485' . random_int(10000000, 99999999),
                    'email' => $customerEmail,
                    'street_name' => 'Firmowa',
                    'street_number' => (string) random_int(1, 120),
                    'city' => $city,
                    'zip_code' => sprintf('%02d-%03d', random_int(10, 99), random_int(100, 999)),
                    'country' => 'PL',
                    'department' => null,
                    'parcel_external_id' => null,
                    'parcel_name' => null,
                    'address_class' => 'company',
                    'company_tax_number' => 'PL' . random_int(1000000000, 9999999999),
                    'company_name' => 'Firma ' . $customerName,
                    'payload_json' => json_encode(['type' => 'invoice'], JSON_UNESCAPED_UNICODE),
                    'created_at' => $now->format('Y-m-d H:i:s'),
                    'updated_at' => $now->format('Y-m-d H:i:s'),
                ]);
            }

            $itemsCount = random_int(1, 5);
            for ($j = 1; $j <= $itemsCount; $j++) {
                $itemType = $itemTypes[array_rand($itemTypes)];
                $qty = $itemType === 'product' ? random_int(1, 3) : 1;
                $priceGross = (float) random_int(1500, 12000) / 100.0;
                $priceNet = round($priceGross / 1.23, 2);
                $insertItem->execute([
                    'order_id' => $orderId,
                    'source_item_id' => 'ITEM-' . $orderId . '-' . $j,
                    'external_item_id' => 'EXTI-' . random_int(10000, 99999),
                    'ean' => (string) random_int(1000000000000, 9999999999999),
                    'sku' => 'SKU-' . random_int(10000, 99999),
                    'original_name' => ucfirst($itemType) . ' ' . random_int(1, 999),
                    'original_code' => strtoupper(substr($itemType, 0, 3)) . '-' . random_int(100, 999),
                    'original_price_with_tax' => number_format($priceGross, 2, '.', ''),
                    'original_price_without_tax' => number_format($priceNet, 2, '.', ''),
                    'media_url' => random_int(1, 100) <= 85
                        ? ('https://picsum.photos/seed/order-item-' . $orderId . '-' . $j . '/120/120')
                        : null,
                    'quantity' => number_format((float) $qty, 3, '.', ''),
                    'tax_rate' => 23.00,
                    'item_status' => 'active',
                    'unit' => 'szt.',
                    'item_type' => $itemType,
                    'source_product_id' => 'P-' . random_int(1000, 9999),
                    'source_product_set_id' => null,
                    'sort_order' => $j - 1,
                    'payload_json' => json_encode(['idx' => $j], JSON_UNESCAPED_UNICODE),
                    'created_at' => $now->format('Y-m-d H:i:s'),
                    'updated_at' => $now->format('Y-m-d H:i:s'),
                ]);
            }

            $paymentsCount = random_int(1, 2);
            if ($profile === 'realistic') {
                if ($totalPaid <= 0.00) {
                    $paymentsCount = random_int(0, 1) === 0 ? 0 : 1;
                } elseif ($totalPaid < $totalGross) {
                    $paymentsCount = 1;
                } else {
                    $paymentsCount = random_int(1, 100) <= 75 ? 1 : 2;
                }
            }
            if ($paymentsCount > 0) {
                for ($j = 1; $j <= $paymentsCount; $j++) {
                    $amount = $paymentsCount === 1 || $j < $paymentsCount
                        ? round($totalPaid / $paymentsCount, 2)
                        : round($totalPaid - round(($totalPaid / $paymentsCount) * ($paymentsCount - 1), 2), 2);
                    $insertPayment->execute([
                        'order_id' => $orderId,
                        'source_payment_id' => 'PAY-' . $orderId . '-' . $j,
                        'external_payment_id' => 'EXTP-' . random_int(10000, 99999),
                        'payment_type_id' => $paymentType,
                        'payment_date' => $orderedAt->add(new DateInterval('PT' . random_int(0, 72) . 'H'))->format('Y-m-d H:i:s'),
                        'amount' => number_format(max(0.0, $amount), 2, '.', ''),
                        'currency' => $currency,
                        'comment' => 'Payment #' . $j,
                        'payload_json' => json_encode(['part' => $j], JSON_UNESCAPED_UNICODE),
                        'created_at' => $now->format('Y-m-d H:i:s'),
                        'updated_at' => $now->format('Y-m-d H:i:s'),
                    ]);
                }
            }

            $shipmentsCount = random_int(0, 2);
            if ($profile === 'realistic') {
                if (in_array($status, ['shipped', 'delivered', 'returned'], true)) {
                    $shipmentsCount = random_int(1, 2);
                } elseif ($status === 'packed') {
                    $shipmentsCount = random_int(0, 100) <= 35 ? 1 : 0;
                } else {
                    $shipmentsCount = 0;
                }
            }
            for ($j = 1; $j <= $shipmentsCount; $j++) {
                $insertShipment->execute([
                    'order_id' => $orderId,
                    'source_shipment_id' => 'SHIP-' . $orderId . '-' . $j,
                    'external_shipment_id' => 'EXTS-' . random_int(10000, 99999),
                    'tracking_number' => 'TRK' . random_int(100000000, 999999999),
                    'carrier_provider_id' => $carriers[array_rand($carriers)],
                    'posted_at' => $orderedAt->add(new DateInterval('P' . random_int(1, 6) . 'D'))->format('Y-m-d H:i:s'),
                    'media_uuid' => null,
                    'payload_json' => json_encode(['shipment_no' => $j], JSON_UNESCAPED_UNICODE),
                    'created_at' => $now->format('Y-m-d H:i:s'),
                    'updated_at' => $now->format('Y-m-d H:i:s'),
                ]);
            }

            $documentsCount = random_int(0, 2);
            if ($profile === 'realistic') {
                if ($isInvoice || in_array($status, ['paid', 'processing', 'packed', 'shipped', 'delivered'], true)) {
                    $documentsCount = random_int(1, 100) <= 75 ? 1 : 2;
                } else {
                    $documentsCount = random_int(1, 100) <= 15 ? 1 : 0;
                }
            }
            for ($j = 1; $j <= $documentsCount; $j++) {
                $insertDocument->execute([
                    'order_id' => $orderId,
                    'source_document_id' => 'DOC-' . $orderId . '-' . $j,
                    'external_document_id' => 'EXTD-' . random_int(10000, 99999),
                    'document_number' => 'FV/' . random_int(1, 9999) . '/' . $now->format('Y'),
                    'price_with_tax' => number_format($totalGross, 2, '.', ''),
                    'price_without_tax' => number_format($totalNet, 2, '.', ''),
                    'currency' => $currency,
                    'currency_value' => number_format(1.0, 4, '.', ''),
                    'document_type_id' => 'invoice',
                    'media_uuid' => null,
                    'source_created_at' => $orderedAt->add(new DateInterval('P' . random_int(0, 3) . 'D'))->format('Y-m-d H:i:s'),
                    'payload_json' => json_encode(['document_no' => $j], JSON_UNESCAPED_UNICODE),
                    'created_at' => $now->format('Y-m-d H:i:s'),
                    'updated_at' => $now->format('Y-m-d H:i:s'),
                ]);
            }

            $notesCount = random_int(0, 3);
            for ($j = 1; $j <= $notesCount; $j++) {
                $insertNote->execute([
                    'order_id' => $orderId,
                    'source_note_id' => 'NOTE-' . $orderId . '-' . $j,
                    'note_type' => $noteTypes[array_rand($noteTypes)],
                    'created_at_external' => $orderedAt->add(new DateInterval('PT' . random_int(1, 96) . 'H'))->format('Y-m-d H:i:s'),
                    'comment' => 'Losowa notatka #' . $j . ' dla zamowienia ' . $sourceOrderId,
                    'payload_json' => json_encode(['n' => $j], JSON_UNESCAPED_UNICODE),
                    'created_at' => $now->format('Y-m-d H:i:s'),
                    'updated_at' => $now->format('Y-m-d H:i:s'),
                ]);
            }

            if ($profile === 'realistic') {
                $historyPath = buildStatusPathForFinal($status);
                $historyDate = $orderedAt;
                for ($j = 1; $j < count($historyPath); $j++) {
                    $historyDate = $historyDate->add(new DateInterval('PT' . random_int(2, 30) . 'H'));
                    $insertStatusHistory->execute([
                        'order_id' => $orderId,
                        'from_status_id' => $historyPath[$j - 1],
                        'to_status_id' => $historyPath[$j],
                        'changed_at' => $historyDate->format('Y-m-d H:i:s'),
                        'change_source' => ['import', 'manual', 'api', 'sync'][array_rand([0, 1, 2, 3])],
                        'comment' => 'Auto-seed status change',
                        'payload_json' => json_encode(['step' => $j], JSON_UNESCAPED_UNICODE),
                        'created_at' => $now->format('Y-m-d H:i:s'),
                    ]);
                }
            } else {
                $historySteps = random_int(2, 6);
                $currentStatus = 'new';
                $historyDate = $orderedAt;
                for ($j = 1; $j <= $historySteps; $j++) {
                    $nextStatus = $statuses[array_rand($statuses)];
                    $historyDate = $historyDate->add(new DateInterval('PT' . random_int(2, 30) . 'H'));
                    $insertStatusHistory->execute([
                        'order_id' => $orderId,
                        'from_status_id' => $currentStatus,
                        'to_status_id' => $nextStatus,
                        'changed_at' => $historyDate->format('Y-m-d H:i:s'),
                        'change_source' => ['import', 'manual', 'api', 'sync'][array_rand([0, 1, 2, 3])],
                        'comment' => 'Auto-seed status change',
                        'payload_json' => json_encode(['step' => $j], JSON_UNESCAPED_UNICODE),
                        'created_at' => $now->format('Y-m-d H:i:s'),
                    ]);
                    $currentStatus = $nextStatus;
                }
            }

            shuffle($tagIds);
            $assignCount = random_int(0, min(3, count($tagIds)));
            for ($j = 0; $j < $assignCount; $j++) {
                $insertTagLink->execute([
                    'order_id' => $orderId,
                    'tag_dict_id' => $tagIds[$j],
                    'assigned_at' => $orderedAt->add(new DateInterval('PT' . random_int(1, 20) . 'H'))->format('Y-m-d H:i:s'),
                    'payload_json' => json_encode(['auto' => true], JSON_UNESCAPED_UNICODE),
                    'created_at' => $now->format('Y-m-d H:i:s'),
                ]);
            }
        }

        $syncInsert = $pdo->prepare(
            'INSERT INTO integration_order_sync_state (
                integration_id, last_synced_order_updated_at, last_synced_source_order_id, last_synced_external_order_id,
                last_run_at, last_success_at, last_error, created_at, updated_at
             ) VALUES (
                :integration_id, :last_synced_order_updated_at, :last_synced_source_order_id, :last_synced_external_order_id,
                :last_run_at, :last_success_at, :last_error, :created_at, :updated_at
             )'
        );
        for ($i = 1; $i <= 3; $i++) {
            $syncInsert->execute([
                'integration_id' => $i,
                'last_synced_order_updated_at' => $now->format('Y-m-d H:i:s'),
                'last_synced_source_order_id' => 'ORD-' . $i . '-' . $now->format('Ymd') . '-9999',
                'last_synced_external_order_id' => 'EXT-' . random_int(100000, 999999),
                'last_run_at' => $now->format('Y-m-d H:i:s'),
                'last_success_at' => $now->format('Y-m-d H:i:s'),
                'last_error' => null,
                'created_at' => $now->format('Y-m-d H:i:s'),
                'updated_at' => $now->format('Y-m-d H:i:s'),
            ]);
        }

        $pdo->commit();
    } catch (Throwable $exception) {
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }
        throw $exception;
    }

    echo '[seed] inserted orders and child data' . PHP_EOL;
}

/**
 * @param array<string,int> $weights
 */
function weightedChoice(array $weights): string
{
    $sum = array_sum($weights);
    if ($sum <= 0) {
        throw new RuntimeException('Invalid weights.');
    }

    $pick = random_int(1, $sum);
    $running = 0;
    foreach ($weights as $value => $weight) {
        $running += $weight;
        if ($pick <= $running) {
            return (string) $value;
        }
    }

    return (string) array_key_first($weights);
}

/**
 * @return list<string>
 */
function buildStatusPathForFinal(string $finalStatus): array
{
    $happyPath = ['new', 'confirmed', 'paid', 'processing', 'packed', 'shipped', 'delivered'];
    if ($finalStatus === 'new') {
        return ['new'];
    }
    if (in_array($finalStatus, $happyPath, true)) {
        $index = array_search($finalStatus, $happyPath, true);
        return array_slice($happyPath, 0, ((int) $index) + 1);
    }
    if ($finalStatus === 'cancelled') {
        $variants = [
            ['new', 'cancelled'],
            ['new', 'confirmed', 'cancelled'],
            ['new', 'confirmed', 'paid', 'cancelled'],
            ['new', 'confirmed', 'paid', 'processing', 'cancelled'],
        ];
        return $variants[array_rand($variants)];
    }
    if ($finalStatus === 'returned') {
        return ['new', 'confirmed', 'paid', 'processing', 'packed', 'shipped', 'delivered', 'returned'];
    }

    return ['new', $finalStatus];
}

/**
 * @return list<string>
 */
function loadStatusesForSeed(PDO $pdo): array
{
    $fallback = ['new', 'confirmed', 'paid', 'processing', 'packed', 'shipped', 'delivered', 'cancelled', 'returned'];

    try {
        $rows = $pdo->query('SELECT code FROM order_statuses WHERE is_active = 1 ORDER BY sort_order ASC, id ASC')->fetchAll(PDO::FETCH_COLUMN);
    } catch (Throwable) {
        return $fallback;
    }

    if (!is_array($rows)) {
        return $fallback;
    }

    $result = [];
    foreach ($rows as $row) {
        $code = strtolower(trim((string) $row));
        if ($code === '' || in_array($code, $result, true)) {
            continue;
        }
        $result[] = $code;
    }

    return $result === [] ? $fallback : $result;
}

function printSummary(PDO $pdo): void
{
    $tables = [
        'orders',
        'order_addresses',
        'order_items',
        'order_payments',
        'order_shipments',
        'order_documents',
        'order_notes',
        'order_status_history',
        'order_tags_dict',
        'order_tag_links',
        'integration_order_sync_state',
    ];

    echo 'Summary counts:' . PHP_EOL;
    foreach ($tables as $table) {
        $count = (int) $pdo->query('SELECT COUNT(*) FROM ' . $table)->fetchColumn();
        echo '  ' . $table . ': ' . $count . PHP_EOL;
    }
}
