<?php

declare(strict_types=1);

namespace Tests\Support\Api;

use mysqli;
use RuntimeException;

final class ApiSchemaBootstrap
{
    public function __construct(private readonly mysqli $db)
    {
    }

    public function ensureSchema(): void
    {
        foreach ($this->tableStatements() as $name => $sql) {
            $this->execute($name, $sql);
        }

        $this->ensureDepartmentArchiveSchema();
        $this->ensureOrderInvoiceCollectionSchema();
        $this->ensurePriceOverrideSchema();

        foreach ($this->viewStatements() as $name => $sql) {
            $this->execute($name, $sql);
        }
    }

    /**
     * @return array<string, string>
     */
    private function tableStatements(): array
    {
        return [
            'groups' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `groups` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NOT NULL,
    `description` TEXT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'users' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `users` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `customer_number` INT NOT NULL,
    `display_name` VARCHAR(255) NULL,
    `email` VARCHAR(255) NULL,
    `phone_country_code` INT NULL,
    `phone` BIGINT NULL,
    `password` VARCHAR(255) NULL,
    `group_id` INT NOT NULL DEFAULT 0,
    `xlvask_customer_id` VARCHAR(255) NULL,
    `sms_notifications_enabled` TINYINT(1) NOT NULL DEFAULT 0,
    `email_notifications_enabled` TINYINT(1) NOT NULL DEFAULT 0,
    `wash_certificate_email` VARCHAR(255) NULL,
    `two_factor_enabled` TINYINT(1) NOT NULL DEFAULT 0,
    `two_factor_secret` VARCHAR(255) NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_users_customer_number` (`customer_number`),
    KEY `idx_users_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'groups_permissions' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `groups_permissions` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `group_id` INT NOT NULL,
    `permission` VARCHAR(191) NOT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_groups_permissions_group_id` (`group_id`),
    KEY `idx_groups_permissions_permission` (`permission`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'logs' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `logs` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `module` VARCHAR(191) NOT NULL,
    `department` VARCHAR(191) NULL,
    `type` INT NOT NULL,
    `user_id` INT NULL,
    `action` VARCHAR(191) NOT NULL,
    `message` TEXT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_logs_module` (`module`),
    KEY `idx_logs_action` (`action`),
    KEY `idx_logs_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'security_firewall_rules' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `security_firewall_rules` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `action` VARCHAR(16) NOT NULL,
    `target_type` VARCHAR(32) NOT NULL,
    `target_value` VARCHAR(255) NOT NULL,
    `route_pattern` VARCHAR(255) NULL,
    `priority` INT NOT NULL DEFAULT 100,
    `reason` TEXT NULL,
    `enabled` TINYINT(1) NOT NULL DEFAULT 1,
    `expires_at` DATETIME NULL,
    `metadata_json` LONGTEXT NULL,
    `created_by` INT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_security_firewall_rules_active` (`enabled`, `deleted_at`, `expires_at`),
    KEY `idx_security_firewall_rules_target` (`target_type`, `target_value`),
    KEY `idx_security_firewall_rules_priority` (`priority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'security_policy_rules' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `security_policy_rules` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `rule_key` VARCHAR(64) NOT NULL,
    `enabled` TINYINT(1) NOT NULL DEFAULT 1,
    `threshold_count` INT NOT NULL,
    `window_seconds` INT NOT NULL,
    `mode` VARCHAR(16) NOT NULL DEFAULT 'observe',
    `exempt_permission_nodes_json` LONGTEXT NULL,
    `updated_by` INT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uq_security_policy_rules_key` (`rule_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'security_policy_events' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `security_policy_events` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `rule_key` VARCHAR(64) NOT NULL,
    `subject_type` VARCHAR(32) NOT NULL,
    `subject_key` VARCHAR(191) NOT NULL,
    `route_path` VARCHAR(255) NULL,
    `route_template` VARCHAR(255) NULL,
    `method` VARCHAR(16) NULL,
    `source_ip` VARCHAR(64) NULL,
    `customer_number` INT NULL,
    `user_id` INT NULL,
    `subuser_id` INT NULL,
    `metadata_json` LONGTEXT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_security_policy_events_window` (`rule_key`, `subject_type`, `subject_key`, `created_at`),
    KEY `idx_security_policy_events_created` (`created_at`),
    KEY `idx_security_policy_events_customer` (`customer_number`, `created_at`),
    KEY `idx_security_policy_events_ip` (`source_ip`, `created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'security_incidents' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `security_incidents` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `incident_key` VARCHAR(191) NOT NULL,
    `type` VARCHAR(64) NOT NULL,
    `severity` VARCHAR(16) NOT NULL DEFAULT 'medium',
    `status` VARCHAR(32) NOT NULL DEFAULT 'open',
    `title` VARCHAR(255) NOT NULL,
    `source_ip` VARCHAR(64) NULL,
    `customer_number` INT NULL,
    `user_id` INT NULL,
    `subuser_id` INT NULL,
    `route_path` VARCHAR(255) NULL,
    `route_template` VARCHAR(255) NULL,
    `method` VARCHAR(16) NULL,
    `related_rule_id` BIGINT UNSIGNED NULL,
    `related_firewall_rule_id` BIGINT UNSIGNED NULL,
    `occurrence_count` INT NOT NULL DEFAULT 1,
    `metadata_json` LONGTEXT NULL,
    `first_seen_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `last_seen_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `resolved_by` INT NULL,
    `resolved_at` DATETIME NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uq_security_incidents_key` (`incident_key`),
    KEY `idx_security_incidents_status_seen` (`status`, `last_seen_at`),
    KEY `idx_security_incidents_type_seen` (`type`, `last_seen_at`),
    KEY `idx_security_incidents_customer_seen` (`customer_number`, `last_seen_at`),
    KEY `idx_security_incidents_ip_seen` (`source_ip`, `last_seen_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'security_incident_notes' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `security_incident_notes` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `incident_id` BIGINT UNSIGNED NOT NULL,
    `note` TEXT NOT NULL,
    `created_by` INT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_security_incident_notes_incident` (`incident_id`, `created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'departments' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `departments` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NOT NULL,
    `description` TEXT NULL,
    `economic_department_id` INT NOT NULL DEFAULT 0,
    `slack_webhook` TEXT NULL,
    `dimension` INT NOT NULL DEFAULT 0,
    `branding` INT NULL DEFAULT NULL,
    `visible` TINYINT(1) NOT NULL DEFAULT 1,
    `archived` TINYINT(1) NOT NULL DEFAULT 0,
    `custom_pricing_only` TINYINT(1) NOT NULL DEFAULT 0,
    `latitude` DECIMAL(10,7) NOT NULL DEFAULT 0,
    `longitude` DECIMAL(10,7) NOT NULL DEFAULT 0,
    `order_priority` INT NOT NULL DEFAULT 0,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_departments_visible` (`visible`),
    KEY `idx_departments_archived` (`archived`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_variables' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_variables` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department_id` INT NOT NULL,
    `variable` VARCHAR(191) NOT NULL,
    `value` TEXT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_department_variables_department_id` (`department_id`),
    KEY `idx_department_variables_variable` (`variable`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_daily_reports' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_daily_reports` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department_id` INT NOT NULL,
    `water_usage` INT NOT NULL DEFAULT 0,
    `water_usage_morning` INT NOT NULL DEFAULT 0,
    `notes` TEXT NULL,
    `filled_by` INT NOT NULL DEFAULT 0,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_department_daily_reports_department_id` (`department_id`),
    KEY `idx_department_daily_reports_created_at` (`created_at`),
    KEY `idx_department_daily_reports_department_created_at` (`department_id`, `created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_time_bookings_opening_hours' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_time_bookings_opening_hours` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department` INT NOT NULL,
    `monday_start` TIME NULL,
    `monday_end` TIME NULL,
    `tuesday_start` TIME NULL,
    `tuesday_end` TIME NULL,
    `wednesday_start` TIME NULL,
    `wednesday_end` TIME NULL,
    `thursday_start` TIME NULL,
    `thursday_end` TIME NULL,
    `friday_start` TIME NULL,
    `friday_end` TIME NULL,
    `saturday_start` TIME NULL,
    `saturday_end` TIME NULL,
    `sunday_start` TIME NULL,
    `sunday_end` TIME NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_department_time_bookings_opening_hours_department` (`department`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_gates' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_gates` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department` INT NOT NULL,
    `is_entrance` TINYINT(1) NOT NULL DEFAULT 0,
    `is_exit` TINYINT(1) NOT NULL DEFAULT 0,
    `name` VARCHAR(255) NOT NULL,
    `config` LONGTEXT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_department_gates_department` (`department`),
    KEY `idx_department_gates_deleted_at` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'branding' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `branding` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NULL,
    `description` TEXT NULL,
    `cvr` INT NULL,
    `address` VARCHAR(255) NULL,
    `phone_country_code` INT NULL,
    `phone` INT NULL,
    `email` VARCHAR(255) NULL,
    `website` VARCHAR(255) NULL,
    `banner` VARCHAR(255) NULL,
    `logo` VARCHAR(255) NULL,
    `favicon` VARCHAR(255) NULL,
    `signature` VARCHAR(255) NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_branding_deleted_at` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_lanes' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_lanes` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department` INT NOT NULL,
    `name` VARCHAR(255) NOT NULL,
    `relay_in_id` VARCHAR(255) NULL,
    `relay_out_id` VARCHAR(255) NULL,
    `relay_machine_id` VARCHAR(255) NULL,
    `relay_machine_program_picker_id` VARCHAR(255) NULL,
    `relay_machine_cleaner_id` VARCHAR(255) NULL,
    `dynamic_image_id` INT NULL,
    `machine_type_id` INT NULL,
    `selfserve_enabled` TINYINT(1) NOT NULL DEFAULT 1,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_department_lanes_department` (`department`),
    KEY `idx_department_lanes_deleted_at` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_selfserve_conditions' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_selfserve_conditions` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department` INT NOT NULL,
    `lane` INT NULL,
    `product` INT NULL,
    `machine_type_id` INT NULL,
    `condition_id` INT NULL,
    `name` VARCHAR(255) NOT NULL,
    `description` TEXT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_department_selfserve_conditions_department` (`department`),
    KEY `idx_department_selfserve_conditions_lane` (`lane`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_selfserve_condition_rules' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_selfserve_condition_rules` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `condition_id` INT NOT NULL,
    `type` VARCHAR(64) NOT NULL,
    `object_type` VARCHAR(64) NOT NULL,
    `object_id` INT NOT NULL,
    `name` VARCHAR(255) NULL,
    `description` TEXT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_department_selfserve_condition_rules_condition` (`condition_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_selfserve_questions' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_selfserve_questions` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department` INT NOT NULL,
    `lane` INT NULL,
    `product` INT NULL,
    `condition_id` INT NULL,
    `question` VARCHAR(255) NOT NULL,
    `description` TEXT NULL,
    `order_priority` INT NOT NULL DEFAULT 0,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_department_selfserve_questions_department` (`department`),
    KEY `idx_department_selfserve_questions_lane` (`lane`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_selfserve_tasks' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_selfserve_tasks` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department` INT NOT NULL,
    `lane` INT NULL,
    `product` INT NULL,
    `machine_type_id` INT NULL,
    `condition_id` INT NULL,
    `gate_type` VARCHAR(16) NULL DEFAULT 'ALWAYS',
    `gate_ref_id` INT NULL,
    `task` VARCHAR(255) NOT NULL,
    `description` TEXT NULL,
    `order_priority` INT NOT NULL DEFAULT 0,
    `services` JSON NULL,
    `buttons` JSON NULL,
    `dynamic_images_vehicle_type` INT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_department_selfserve_tasks_department` (`department`),
    KEY `idx_department_selfserve_tasks_lane` (`lane`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_selfserve_vehicle_conditions' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_selfserve_vehicle_conditions` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department` INT NOT NULL,
    `lane` INT NULL,
    `customer_id` INT NULL,
    `reg` VARCHAR(64) NULL,
    `question` INT NOT NULL,
    `value` TINYINT(1) NOT NULL DEFAULT 0,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_department_selfserve_vehicle_conditions_department` (`department`),
    KEY `idx_department_selfserve_vehicle_conditions_reg` (`reg`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'selfserve_machine_types' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `selfserve_machine_types` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NOT NULL,
    `description` VARCHAR(255) NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_selfserve_machine_types_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'selfserve_wash_sessions' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `selfserve_wash_sessions` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `lane_id` INT NOT NULL,
    `department_id` INT NOT NULL,
    `machine_type_id` INT NULL,
    `customer_number` INT NULL,
    `subuser_id` INT NULL,
    `vehicle_id` INT NULL,
    `vehicle_type_id` INT NULL,
    `reg` VARCHAR(255) NOT NULL,
    `status` VARCHAR(64) NOT NULL DEFAULT 'PENDING_QUESTIONS',
    `allowed` TINYINT(1) NOT NULL DEFAULT 0,
    `machine_relay_enabled` TINYINT(1) NOT NULL DEFAULT 0,
    `machine_relay_enabled_at` DATETIME NULL,
    `machine_start_triggered` TINYINT(1) NOT NULL DEFAULT 0,
    `machine_start_triggered_at` DATETIME NULL,
    `wash_started_at` DATETIME NULL,
    `order_id` INT NULL,
    `completed_at` DATETIME NULL,
    `metadata_json` JSON NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_selfserve_wash_sessions_lane_reg` (`lane_id`, `reg`),
    KEY `idx_selfserve_wash_sessions_status` (`status`),
    KEY `idx_selfserve_wash_sessions_customer` (`customer_number`),
    KEY `idx_selfserve_wash_sessions_subuser_active` (`subuser_id`, `completed_at`),
    KEY `idx_selfserve_wash_sessions_customer_subuser_active` (`customer_number`, `subuser_id`, `completed_at`),
    KEY `idx_selfserve_wash_sessions_department_completed` (`department_id`, `completed_at`),
    KEY `idx_selfserve_wash_sessions_order` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'selfserve_wash_session_answers' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `selfserve_wash_session_answers` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `session_id` INT NOT NULL,
    `question_id` INT NOT NULL,
    `question_text` VARCHAR(255) NOT NULL,
    `answer_value` TINYINT(1) NOT NULL,
    `answered_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_selfserve_wash_session_answer` (`session_id`, `question_id`),
    KEY `idx_selfserve_wash_session_answers_session` (`session_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'selfserve_wash_session_tasks' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `selfserve_wash_session_tasks` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `session_id` INT NOT NULL,
    `task_id` INT NULL,
    `task_text` VARCHAR(255) NOT NULL,
    `description` TEXT NULL,
    `services` JSON NULL,
    `buttons` JSON NULL,
    `dynamic_image_id` INT NULL,
    `dynamic_images_vehicle_type` INT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_selfserve_wash_session_tasks_session` (`session_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'selfserve_wash_session_events' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `selfserve_wash_session_events` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `session_id` INT NOT NULL,
    `event_type` VARCHAR(64) NOT NULL,
    `payload_json` JSON NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_selfserve_wash_session_events_session` (`session_id`),
    KEY `idx_selfserve_wash_session_events_type` (`event_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'plate_scanners' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `plate_scanners` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department_id` INT NOT NULL,
    `lane_id` INT NULL,
    `name` VARCHAR(255) NOT NULL,
    `notes` TEXT NULL,
    `api_key` VARCHAR(191) NOT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_plate_scanners_department_id` (`department_id`),
    KEY `idx_plate_scanners_lane_id` (`lane_id`),
    KEY `idx_plate_scanners_api_key` (`api_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'categories' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `categories` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NOT NULL,
    `description` TEXT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'products' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `products` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) NOT NULL,
    `description` TEXT NULL,
    `price` INT NOT NULL DEFAULT 0,
    `subscription_allowed` TINYINT(1) NOT NULL DEFAULT 0,
    `category` INT NOT NULL DEFAULT 0,
    `piktogram` VARCHAR(255) NULL,
    `economic_product_id` INT NULL,
    `apply_category_discount` TINYINT(1) NOT NULL DEFAULT 1,
    `requires_note` TINYINT(1) NOT NULL DEFAULT 0,
    `is_wash` TINYINT(1) NOT NULL DEFAULT 0,
    `display_in_booking_form` TINYINT(1) NOT NULL DEFAULT 0,
    `order_priority` INT NOT NULL DEFAULT 0,
    `max_quantity_per_order` INT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_products_category` (`category`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_categories' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_categories` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department_id` INT NOT NULL,
    `category_id` INT NOT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_department_categories_department_id` (`department_id`),
    KEY `idx_department_categories_category_id` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'product_department_prices' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `product_department_prices` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department_id` INT NOT NULL,
    `product_id` INT NOT NULL,
    `price` INT NOT NULL DEFAULT 0,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_product_department_prices_lookup` (`department_id`, `product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'limited_backoffice_employees' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `limited_backoffice_employees` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `user_id` INT NOT NULL,
    `managed_group_id` INT NOT NULL,
    `role_key` VARCHAR(64) NOT NULL,
    `department_ids` LONGTEXT NOT NULL,
    `created_by_user_id` INT NOT NULL,
    `updated_by_user_id` INT NULL,
    `deactivated_at` DATETIME NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_limited_backoffice_employees_user_id` (`user_id`),
    KEY `idx_limited_backoffice_employees_group_id` (`managed_group_id`),
    KEY `idx_limited_backoffice_employees_role_key` (`role_key`),
    KEY `idx_limited_backoffice_employees_deactivated_at` (`deactivated_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'collected_order_invoices' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `collected_order_invoices` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `customer_number` INT NOT NULL,
    `name` VARCHAR(255) NOT NULL,
    `notes` TEXT NULL,
    `processor` INT NOT NULL DEFAULT 0,
    `external_id` VARCHAR(255) NULL,
    `booked_invoice_id` INT NULL,
    `po_number` VARCHAR(255) NULL,
    `error_message` TEXT NULL,
    `closed_at` DATETIME NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_collected_order_invoices_customer_number` (`customer_number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'orders' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `orders` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `customer_id` INT NOT NULL,
    `cashier_id` INT NOT NULL DEFAULT 0,
    `department_id` INT NOT NULL,
    `reference` VARCHAR(255) NOT NULL,
    `notes` TEXT NULL,
    `reg_1` VARCHAR(32) NULL,
    `reg_2` VARCHAR(32) NULL,
    `reg_3` VARCHAR(32) NULL,
    `invoice_collection_id` INT NULL,
    `booking_id` INT NULL,
    `wash_id` VARCHAR(255) NULL,
    `lane` INT NULL,
    `po` VARCHAR(255) NULL,
    `safety_seal` VARCHAR(255) NULL,
    `using_hand_held` TINYINT(1) NOT NULL DEFAULT 0,
    `include_in_invoice` TINYINT(1) NOT NULL DEFAULT 1,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `completed_at` DATETIME NULL,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_orders_customer_id` (`customer_id`),
    KEY `idx_orders_department_id` (`department_id`),
    KEY `idx_orders_invoice_collection_id` (`invoice_collection_id`),
    KEY `idx_orders_reg_1` (`reg_1`),
    KEY `idx_orders_period_customer_created_deleted` (`customer_id`, `created_at`, `deleted_at`),
    KEY `idx_orders_period_created_deleted_customer` (`created_at`, `deleted_at`, `customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'bookings' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `bookings` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `customer_number` INT NOT NULL,
    `wash_type` VARCHAR(255) NULL,
    `contact_email` VARCHAR(255) NULL,
    `reference_number` VARCHAR(255) NULL,
    `regNrTraekker` VARCHAR(32) NULL,
    `regNrTrailer` VARCHAR(32) NULL,
    `washCertificateEmail` VARCHAR(255) NULL,
    `date` DATETIME NULL,
    `department` INT NOT NULL DEFAULT 0,
    `pickup_bool` TINYINT(1) NOT NULL DEFAULT 0,
    `notes` TEXT NULL,
    `washCertificateStatus` VARCHAR(32) NULL,
    `washCertificateUrl` TEXT NULL,
    `wash_certificate_pdf` VARCHAR(255) NULL,
    `status` VARCHAR(32) NULL,
    `data` LONGTEXT NULL,
    `virtual_cart` TINYINT(1) NOT NULL DEFAULT 0,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_bookings_customer_number` (`customer_number`),
    KEY `idx_bookings_department` (`department`),
    KEY `idx_bookings_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'order_bookings' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `order_bookings` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `customer_number` INT NOT NULL,
    `department` INT NOT NULL,
    `reg_1` VARCHAR(32) NULL,
    `reg_2` VARCHAR(32) NULL,
    `reg_3` VARCHAR(32) NULL,
    `datetime` DATETIME NULL,
    `note` TEXT NULL,
    `reference` VARCHAR(255) NULL,
    `po` VARCHAR(255) NULL,
    `pickup` TINYINT(1) NOT NULL DEFAULT 0,
    `items` LONGTEXT NULL,
    `order_id` INT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_order_bookings_department` (`department`),
    KEY `idx_order_bookings_customer_number` (`customer_number`),
    KEY `idx_order_bookings_order_id` (`order_id`),
    KEY `idx_order_bookings_reg_1` (`reg_1`),
    KEY `idx_order_bookings_deleted_at` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'order_items' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `order_items` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `order_id` INT NOT NULL,
    `product_id` INT NOT NULL,
    `reference` VARCHAR(255) NULL,
    `notes` TEXT NULL,
    `cashier_id` INT NOT NULL DEFAULT 0,
    `price` INT NOT NULL DEFAULT 0,
    `quantity` INT NOT NULL DEFAULT 1,
    `related_item_id` INT NULL,
    `include_in_invoice` TINYINT(1) NOT NULL DEFAULT 1,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_order_items_order_id` (`order_id`),
    KEY `idx_order_items_deleted_at` (`deleted_at`),
    KEY `idx_order_items_order_deleted` (`order_id`, `deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'customer_vehicles' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `customer_vehicles` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `customer_id` INT NOT NULL,
    `type` INT NOT NULL DEFAULT 0,
    `reg` VARCHAR(32) NOT NULL,
    `wash_subscription` TINYINT(1) NOT NULL DEFAULT 0,
    `notes` TEXT NULL,
    `reference` VARCHAR(255) NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_customer_vehicles_customer_id` (`customer_id`),
    KEY `idx_customer_vehicles_reg` (`reg`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'xlvask_vehicle_types' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `xlvask_vehicle_types` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `vehicleTypeId` VARCHAR(255) NOT NULL,
    `name` VARCHAR(255) NULL,
    `product` INT NOT NULL DEFAULT 0,
    `created_at` INT NOT NULL DEFAULT 0,
    `updated_at` INT NOT NULL DEFAULT 0,
    PRIMARY KEY (`id`),
    KEY `idx_xlvask_vehicle_types_product` (`product`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'xlvask_usage_logs' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `xlvask_usage_logs` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `WashId` VARCHAR(191) NOT NULL,
    `CustomerId` VARCHAR(191) NULL,
    `Customer` VARCHAR(255) NULL,
    `VatNumber` VARCHAR(64) NULL,
    `Location` VARCHAR(255) NULL,
    `Hall` VARCHAR(255) NULL,
    `HallId` VARCHAR(191) NULL,
    `StartTime` VARCHAR(64) NULL,
    `FinishTime` VARCHAR(64) NULL,
    `RegistrationNumber` VARCHAR(64) NULL,
    `VehicleType` VARCHAR(191) NULL,
    `IdentificationType` VARCHAR(191) NULL,
    `IdentificationId` VARCHAR(191) NULL,
    `Info` TEXT NULL,
    `Updated` VARCHAR(64) NULL,
    `Prepaid` VARCHAR(64) NULL,
    `FinishStatus` VARCHAR(64) NULL,
    `CustomerGuid` VARCHAR(191) NULL,
    `VehicleId` VARCHAR(191) NULL,
    `WashItems` LONGTEXT NULL,
    `ignored_at` DATETIME NULL,
    `ignored_by` INT NULL,
    `ignored_reason` TEXT NULL,
    `cached_total_net_amount` DECIMAL(12,2) NULL,
    `cached_primary_product_name` VARCHAR(255) NULL,
    `cached_amount_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_xlvask_usage_logs_wash_id` (`WashId`),
    KEY `idx_xlvask_usage_logs_customer` (`CustomerId`),
    KEY `idx_xlvask_usage_logs_start` (`StartTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'customer_vehicles_addons' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `customer_vehicles_addons` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `vehicle_id` INT NOT NULL,
    `addon_id` INT NOT NULL,
    `amount` INT NOT NULL DEFAULT 1,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_customer_vehicles_addons_vehicle_id` (`vehicle_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'subusers' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `subusers` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `username` VARCHAR(255) NULL,
    `password` VARCHAR(255) NULL,
    `name` VARCHAR(255) NULL,
    `email` VARCHAR(255) NULL,
    `email_verified_at` DATETIME NULL,
    `phone_country_code` INT NULL,
    `phone` BIGINT NULL,
    `phone_verified_at` DATETIME NULL,
    `two_factor_enabled` TINYINT(1) NOT NULL DEFAULT 0,
    `two_factor_secret` VARCHAR(255) NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `suspended_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_subusers_username` (`username`),
    KEY `idx_subusers_phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'subuser_grants' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `subuser_grants` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `billing_customer_number` INT NOT NULL,
    `subuser` INT NOT NULL,
    `assigned_vehicle_id` INT NULL,
    `enabled` TINYINT(1) NOT NULL DEFAULT 1,
    `note` TEXT NULL,
    `permissions` LONGTEXT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_subuser_grants_subuser` (`subuser`),
    KEY `idx_subuser_grants_assigned_vehicle_id` (`assigned_vehicle_id`),
    KEY `idx_subuser_grants_billing_customer_number` (`billing_customer_number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'tokens' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `tokens` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `user_id` INT NOT NULL,
    `type` VARCHAR(64) NOT NULL,
    `description` VARCHAR(255) NULL,
    `token` VARCHAR(255) NOT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_tokens_token` (`token`),
    KEY `idx_tokens_user_id` (`user_id`),
    KEY `idx_tokens_type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'passkeys' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `passkeys` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `user_id` INT NOT NULL,
    `is_subuser` TINYINT(1) NOT NULL DEFAULT 0,
    `credential_id` VARCHAR(4096) NOT NULL,
    `public_key` TEXT NOT NULL,
    `algorithm` VARCHAR(32) NOT NULL,
    `transports` JSON NULL,
    `sign_count` INT NOT NULL DEFAULT 0,
    `backup_state` JSON NULL,
    `name` VARCHAR(255) NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_passkeys_user` (`user_id`, `is_subuser`),
    KEY `idx_passkeys_deleted_at` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'customer_attributes' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `customer_attributes` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `user_id` INT NOT NULL,
    `attribute` VARCHAR(191) NOT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_customer_attributes_user_id` (`user_id`),
    KEY `idx_customer_attributes_attribute` (`attribute`),
    KEY `idx_customer_attributes_attribute_user` (`attribute`, `user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'customer_rule_product_restrictions' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `customer_rule_product_restrictions` (
    `attribute` VARCHAR(191) NOT NULL,
    `version` INT UNSIGNED NOT NULL DEFAULT 1,
    `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`attribute`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'customer_rule_product_collections' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `customer_rule_product_collections` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `attribute` VARCHAR(191) NOT NULL,
    `name` VARCHAR(191) NOT NULL,
    `sort_order` INT NOT NULL DEFAULT 0,
    `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_customer_rule_collection_name` (`attribute`, `name`),
    KEY `idx_customer_rule_collection_attribute_order` (`attribute`, `sort_order`, `id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'customer_rule_product_collection_products' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `customer_rule_product_collection_products` (
    `collection_id` INT UNSIGNED NOT NULL,
    `product_id` INT UNSIGNED NOT NULL,
    `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`collection_id`, `product_id`),
    KEY `idx_customer_rule_collection_product` (`product_id`, `collection_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'customer_rule_product_migrations' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `customer_rule_product_migrations` (
    `migration_key` VARCHAR(191) NOT NULL,
    `details_json` LONGTEXT NULL,
    `applied_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`migration_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'customer_rule_product_audit_logs' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `customer_rule_product_audit_logs` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `actor_user_id` INT UNSIGNED NULL,
    `attribute` VARCHAR(191) NOT NULL,
    `old_version` INT UNSIGNED NOT NULL,
    `new_version` INT UNSIGNED NOT NULL,
    `changes_json` LONGTEXT NOT NULL,
    `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_customer_rule_product_audit_attribute` (`attribute`, `created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'module_config' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `module_config` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `module` VARCHAR(191) NOT NULL,
    `variable` VARCHAR(191) NOT NULL,
    `value` LONGTEXT NULL,
    `type` VARCHAR(64) NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_module_config_module_variable` (`module`, `variable`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'user_key_value_pairs' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `user_key_value_pairs` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `user_id` INT NOT NULL,
    `var` VARCHAR(191) NOT NULL,
    `val` LONGTEXT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_user_key_value_pairs_user_id` (`user_id`),
    KEY `idx_user_key_value_pairs_var` (`var`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'price_overrides' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `price_overrides` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `user_id` INT NOT NULL,
    `is_category` TINYINT(1) NOT NULL DEFAULT 0,
    `product_or_category_id` VARCHAR(191) NOT NULL,
    `percentage` INT NOT NULL DEFAULT 0,
    `fixed_price` INT NULL DEFAULT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_price_overrides_user_id` (`user_id`),
    KEY `idx_price_overrides_lookup` (`user_id`, `is_category`, `product_or_category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'department_customer_price_overrides' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `department_customer_price_overrides` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `department_id` INT NOT NULL,
    `user_id` INT NOT NULL,
    `is_category` TINYINT(1) NOT NULL DEFAULT 0,
    `product_or_category_id` VARCHAR(191) NOT NULL,
    `percentage` INT NOT NULL DEFAULT 0,
    `fixed_price` INT NULL DEFAULT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_department_customer_price_overrides_lookup` (`department_id`, `user_id`, `is_category`, `product_or_category_id`),
    KEY `idx_department_customer_price_overrides_department` (`department_id`),
    KEY `idx_department_customer_price_overrides_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'products_options' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `products_options` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `product_id` INT NOT NULL,
    `option_id` INT NOT NULL,
    `name` VARCHAR(255) NULL,
    `min` INT NULL,
    `max` INT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_products_options_product_id` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'economic_module_orders' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `economic_module_orders` (
    `id` INT NOT NULL,
    `invoice_draft_id` INT NULL,
    `invoice_id` INT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'stripe_module_orders' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `stripe_module_orders` (
    `id` INT NOT NULL,
    `invoice_id` VARCHAR(255) NULL,
    `customer_id` VARCHAR(255) NULL,
    `email_sent` DATETIME NULL,
    `url` TEXT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'stripe_module_customers' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `stripe_module_customers` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `email` VARCHAR(255) NOT NULL,
    `customer_id` VARCHAR(255) NOT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_stripe_module_customers_email` (`email`),
    KEY `idx_stripe_module_customers_customer_id` (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'stripe_payment_intents' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `stripe_payment_intents` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `order_id` INT NOT NULL,
    `payment_intent_id` VARCHAR(255) NOT NULL,
    `client_secret` VARCHAR(255) NULL,
    `data` LONGTEXT NULL,
    `reader_id` VARCHAR(255) NULL,
    `tax_percentage` INT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_stripe_payment_intents_order_id` (`order_id`),
    KEY `idx_stripe_payment_intents_payment_intent_id` (`payment_intent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'object_attachments' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `object_attachments` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `object_type` VARCHAR(191) NOT NULL,
    `object_id` INT NOT NULL,
    `content` LONGTEXT NULL,
    `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `deleted_at` DATETIME NULL,
    PRIMARY KEY (`id`),
    KEY `idx_object_attachments_lookup` (`object_type`, `object_id`),
    KEY `idx_object_attachments_deleted_at` (`deleted_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
            'invoice_period_flags' => <<<'SQL'
CREATE TABLE IF NOT EXISTS `invoice_period_flags` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `source` VARCHAR(32) NOT NULL,
    `severity` VARCHAR(32) NOT NULL,
    `status` VARCHAR(32) NOT NULL DEFAULT 'active',
    `target_type` VARCHAR(64) NOT NULL,
    `target_id` BIGINT NOT NULL,
    `field` VARCHAR(64) NULL,
    `customer_number` INT NULL,
    `order_id` BIGINT NULL,
    `order_item_id` BIGINT NULL,
    `invoice_collection_id` BIGINT NULL,
    `xlvask_usage_log_id` BIGINT NULL,
    `definition_key` VARCHAR(128) NULL,
    `fingerprint` VARCHAR(191) NULL,
    `reason` TEXT NULL,
    `status_reason` TEXT NULL,
    `context_json` JSON NULL,
    `created_by` INT NULL,
    `status_changed_by` INT NULL,
    `status_changed_at` DATETIME NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uniq_invoice_period_flags_auto_fingerprint` (`source`, `fingerprint`),
    KEY `idx_invoice_period_flags_target` (`target_type`, `target_id`, `status`),
    KEY `idx_invoice_period_flags_customer_status` (`customer_number`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
        ];
    }

    /**
     * @return array<string, string>
     */
    private function viewStatements(): array
    {
        return [
            'orders_with_invoice_collections' => <<<'SQL'
CREATE OR REPLACE VIEW `orders_with_invoice_collections` AS
SELECT
    o.*,
    coi.closed_at,
    coi.booked_invoice_id,
    coi.processor
FROM `orders` o
LEFT JOIN `collected_order_invoices` coi ON coi.id = o.invoice_collection_id
SQL,
        ];
    }

    private function execute(string $name, string $sql): void
    {
        if ($this->db->query($sql) === false) {
            throw new RuntimeException(
                sprintf('Failed to bootstrap API test schema for "%s": %s', $name, (string)$this->db->error)
            );
        }
    }

    private function ensureDepartmentArchiveSchema(): void
    {
        if (!$this->columnExists('departments', 'archived')) {
            $this->execute(
                'departments.archived',
                'ALTER TABLE `departments` ADD COLUMN `archived` TINYINT(1) NOT NULL DEFAULT 0 AFTER `visible`'
            );
        }

        if (!$this->indexExists('departments', 'idx_departments_archived')) {
            $this->execute(
                'departments.idx_departments_archived',
                'ALTER TABLE `departments` ADD INDEX `idx_departments_archived` (`archived`)'
            );
        }

        if (!$this->columnExists('departments', 'custom_pricing_only')) {
            $this->execute(
                'departments.custom_pricing_only',
                'ALTER TABLE `departments` ADD COLUMN `custom_pricing_only` TINYINT(1) NOT NULL DEFAULT 0 AFTER `archived`'
            );
        }
    }

    private function ensureOrderInvoiceCollectionSchema(): void
    {
        if (!$this->columnExists('orders', 'invoice_collection_id')) {
            $this->execute(
                'orders.invoice_collection_id',
                'ALTER TABLE `orders` ADD COLUMN `invoice_collection_id` INT NULL'
            );
        }

        if (!$this->indexExists('orders', 'idx_orders_invoice_collection_id')) {
            $this->execute(
                'orders.idx_orders_invoice_collection_id',
                'ALTER TABLE `orders` ADD INDEX `idx_orders_invoice_collection_id` (`invoice_collection_id`)'
            );
        }

        if (!$this->columnExists('collected_order_invoices', 'processor')) {
            $this->execute(
                'collected_order_invoices.processor',
                'ALTER TABLE `collected_order_invoices` ADD COLUMN `processor` INT NOT NULL DEFAULT 0'
            );
        }

        if (!$this->columnExists('collected_order_invoices', 'booked_invoice_id')) {
            $this->execute(
                'collected_order_invoices.booked_invoice_id',
                'ALTER TABLE `collected_order_invoices` ADD COLUMN `booked_invoice_id` INT NULL'
            );
        }

        if (!$this->columnExists('collected_order_invoices', 'closed_at')) {
            $this->execute(
                'collected_order_invoices.closed_at',
                'ALTER TABLE `collected_order_invoices` ADD COLUMN `closed_at` DATETIME NULL'
            );
        }
    }

    private function ensurePriceOverrideSchema(): void
    {
        if (!$this->columnExists('price_overrides', 'fixed_price')) {
            $this->execute(
                'price_overrides.fixed_price',
                'ALTER TABLE `price_overrides` ADD COLUMN `fixed_price` INT NULL DEFAULT NULL AFTER `percentage`'
            );
        }
    }

    private function columnExists(string $table, string $column): bool
    {
        $table = $this->db->real_escape_string($table);
        $column = $this->db->real_escape_string($column);
        $result = $this->db->query("SHOW COLUMNS FROM `{$table}` LIKE '{$column}'");

        return $result !== false && $result->num_rows > 0;
    }

    private function indexExists(string $table, string $index): bool
    {
        $table = $this->db->real_escape_string($table);
        $index = $this->db->real_escape_string($index);
        $result = $this->db->query("SHOW INDEX FROM `{$table}` WHERE Key_name = '{$index}'");

        return $result !== false && $result->num_rows > 0;
    }
}
