<?php
declare(strict_types=1);

namespace App\Modules\Shipments;

use PDO;

final class ShipmentPresetRepository
{
    public function __construct(
        private readonly PDO $pdo
    ) {
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    public function findAll(): array
    {
        $statement = $this->pdo->prepare(
            'SELECT * FROM shipment_presets ORDER BY sort_order ASC, id ASC'
        );
        $statement->execute();
        return $statement->fetchAll(PDO::FETCH_ASSOC) ?: [];
    }

    /**
     * @return array<string, mixed>|null
     */
    public function findById(int $id): ?array
    {
        $statement = $this->pdo->prepare('SELECT * FROM shipment_presets WHERE id = :id LIMIT 1');
        $statement->execute(['id' => $id]);
        $row = $statement->fetch(PDO::FETCH_ASSOC);
        return is_array($row) ? $row : null;
    }

    /**
     * @param array<string, mixed> $data
     */
    public function create(array $data): int
    {
        $statement = $this->pdo->prepare(
            'INSERT INTO shipment_presets (
                name, color, carrier, provider_code, delivery_method_id,
                credentials_id, carrier_id, package_type,
                length_cm, width_cm, height_cm, weight_kg,
                sender_point_id, label_format, sort_order
            ) VALUES (
                :name, :color, :carrier, :provider_code, :delivery_method_id,
                :credentials_id, :carrier_id, :package_type,
                :length_cm, :width_cm, :height_cm, :weight_kg,
                :sender_point_id, :label_format, :sort_order
            )'
        );

        $statement->execute($this->mapParams($data));

        return (int) $this->pdo->lastInsertId();
    }

    /**
     * @param array<string, mixed> $data
     */
    public function update(int $id, array $data): void
    {
        $statement = $this->pdo->prepare(
            'UPDATE shipment_presets SET
                name = :name, color = :color, carrier = :carrier,
                provider_code = :provider_code, delivery_method_id = :delivery_method_id,
                credentials_id = :credentials_id, carrier_id = :carrier_id,
                package_type = :package_type,
                length_cm = :length_cm, width_cm = :width_cm,
                height_cm = :height_cm, weight_kg = :weight_kg,
                sender_point_id = :sender_point_id, label_format = :label_format,
                sort_order = :sort_order
            WHERE id = :id'
        );

        $params = $this->mapParams($data);
        $params['id'] = $id;
        $statement->execute($params);
    }

    public function delete(int $id): void
    {
        $statement = $this->pdo->prepare('DELETE FROM shipment_presets WHERE id = :id');
        $statement->execute(['id' => $id]);
    }

    /**
     * @param array<string, mixed> $data
     * @return array<string, mixed>
     */
    private function mapParams(array $data): array
    {
        return [
            'name' => trim((string) ($data['name'] ?? '')),
            'color' => trim((string) ($data['color'] ?? '#3b82f6')),
            'carrier' => trim((string) ($data['carrier'] ?? '')),
            'provider_code' => trim((string) ($data['provider_code'] ?? '')),
            'delivery_method_id' => trim((string) ($data['delivery_method_id'] ?? '')),
            'credentials_id' => trim((string) ($data['credentials_id'] ?? '')),
            'carrier_id' => trim((string) ($data['carrier_id'] ?? '')),
            'package_type' => trim((string) ($data['package_type'] ?? 'PACKAGE')),
            'length_cm' => max(0.1, (float) ($data['length_cm'] ?? 25.0)),
            'width_cm' => max(0.1, (float) ($data['width_cm'] ?? 20.0)),
            'height_cm' => max(0.1, (float) ($data['height_cm'] ?? 8.0)),
            'weight_kg' => max(0.001, (float) ($data['weight_kg'] ?? 1.0)),
            'sender_point_id' => trim((string) ($data['sender_point_id'] ?? '')),
            'label_format' => in_array(strtoupper(trim((string) ($data['label_format'] ?? ''))), ['PDF', 'ZPL'], true)
                ? strtoupper(trim((string) $data['label_format']))
                : 'PDF',
            'sort_order' => max(0, (int) ($data['sort_order'] ?? 0)),
        ];
    }
}
