<?php
/**
 * BookiFlex Core
 *
 * @package    BookiFlex
 * @subpackage Core
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Core\ORM;

use BookiFlex\Core;
use BookiFlex\Core\Contract\Adjustment\AdjustmentMode;
use BookiFlex\Core\Contract\Adjustment\AdjustmentStrategy;
use BookiFlex\Core\Contract\Adjustment\AdjustmentType;
use BookiFlex\Core\Model\AccommodationType\Accommodation\AccommodationType;
use BookiFlex\Core\Model\CancellationPolicy\CancellationPolicy;
use BookiFlex\Core\Model\Customer\Customer;
use BookiFlex\Core\Model\PaymentType\PaymentType;
use BookiFlex\Core\Model\RatePlan\RatePlan;
use BookiFlex\Core\Model\Reservation\Adjustment;
use BookiFlex\Core\Model\Reservation\Reservation;
use BookiFlex\Core\ORM\Mapper\ReadOnlyMapper;
use BookiFlex\Core\ORM\Schema\DateUnitSchema;
use BookiFlex\Core\Repository\AccommodationTypeRepository;
use BookiFlex\Core\Repository\PaymentTypeRepository;
use BookiFlex\Core\Repository\RatePlanRepository;
use Cycle\ORM;

defined( 'ABSPATH' ) || exit;

class CoreSchema
{
    public static function getSchema(): array
    {
		global $wpdb;

        return [
            'accommodationType' => [
                ORM\SchemaInterface::MAPPER      => ReadOnlyMapper::class, // default POPO mapper
                ORM\SchemaInterface::ENTITY      => AccommodationType::class,
                ORM\SchemaInterface::REPOSITORY  => AccommodationTypeRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => $wpdb->posts,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',

                // property => column
                ORM\SchemaInterface::COLUMNS => [
                    'id'          => 'id',
                    'name'        => 'post_title',
//                    'description' => 'post_excerpt',
                ],

                ORM\SchemaInterface::TYPECAST => [
                    'id'                    => 'int',
                    'name'                  => 'string',
                    'accommodationCategory' => 'string',
                    'accommodationAvailableUnits'      => 'int',
                ],

                ORM\SchemaInterface::TYPECAST_HANDLER => [
                    ORM\Parser\Typecast::class,
                    Core\ORM\Typecast\AccommodationTypeTypecast::class,
//                    Core\ORM\Typecast\WPEntityTypecast::class
                ],
            ],
            'ratePlan' => [
                ORM\SchemaInterface::MAPPER      => ReadOnlyMapper::class, // default POPO mapper
                ORM\SchemaInterface::ENTITY      => RatePlan::class,
                ORM\SchemaInterface::REPOSITORY  => RatePlanRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => $wpdb->posts,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',

                // property => column
                ORM\SchemaInterface::COLUMNS => [
                    'id'          => 'id',
                    'name'        => 'post_title',
                    'description' => 'post_excerpt',
                ],

                ORM\SchemaInterface::TYPECAST => [
                    'id'          => 'int',
                    'boardType'   => Core\Model\RatePlan\BoardType::class,
                    'name'        => 'string',
                    'description' => 'string',
                    'content'     => 'string',
                    'code'        => 'string',
                ],

                ORM\SchemaInterface::TYPECAST_HANDLER => [
                    ORM\Parser\Typecast::class,
                ],

                ORM\SchemaInterface::RELATIONS => [
                    'parent' => [
                        ORM\Relation::TYPE   => ORM\Relation::HAS_ONE,
                        ORM\Relation::TARGET => 'ratePlan',
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::NULLABLE  => true,
                            ORM\Relation::CASCADE   => false,
                            ORM\Relation::INNER_KEY => 'id',
                            ORM\Relation::OUTER_KEY => 'id',
                        ],
                    ],
                    'accommodationTypes' => [
                        ORM\Relation::TYPE   => ORM\Relation::MORPHED_HAS_MANY,
                        ORM\Relation::TARGET => 'accommodationType',
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::MORPH_KEY => 'accommodationTypes_role',
                            ORM\Relation::CASCADE   => false,
                            ORM\Relation::INNER_KEY => 'id',
                            ORM\Relation::OUTER_KEY => 'id',
                        ],
                    ],
                    'paymentTypes' => [
                        ORM\Relation::TYPE   => ORM\Relation::MORPHED_HAS_MANY,
                        ORM\Relation::TARGET => 'paymentType',
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::MORPH_KEY => 'paymentTypes_role',
                            ORM\Relation::CASCADE   => false,
                            ORM\Relation::INNER_KEY => 'id',
                            ORM\Relation::OUTER_KEY => 'id',
                        ],
                    ],
                    'cancellationPolicy' => [
                        ORM\Relation::TYPE   => ORM\Relation::MORPHED_HAS_MANY,
                        ORM\Relation::TARGET => 'cancellationPolicy',
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::MORPH_KEY => 'cancellationPolicy_role',
                            ORM\Relation::CASCADE   => false,
                            ORM\Relation::INNER_KEY => 'id',
                            ORM\Relation::OUTER_KEY => 'id',
                        ],
                    ],
                ],
            ],
            'paymentType' => [
                ORM\SchemaInterface::MAPPER      => ReadOnlyMapper::class, // default POPO mapper
                ORM\SchemaInterface::ENTITY      => PaymentType::class,
                ORM\SchemaInterface::REPOSITORY  => PaymentTypeRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => $wpdb->posts,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',

                // property => column
                ORM\SchemaInterface::COLUMNS => [
                    'id'          => 'id',
                    'name'        => 'post_title',
                    'description' => 'post_excerpt',
                ],

                ORM\SchemaInterface::TYPECAST => [
                    'id' => 'int',
//                    'active' => 'bool', // by rules
                    'name'                 => 'string',
                    'description'          => 'string',
                    'type'                 => 'string',
                    // 'payable' is now a computed property in model (based on 'type')
                    'paymentAuthorization' => 'bool',
                    'prepaymentType'       => 'string',
                    'prepaymentValue'      => 'int',
                    'ABAPeriod'            => 'string',
                    'ABACondition'         => 'string',
                    'ABAValue'             => 'int',
                    'gatewayName'          => 'string',
                    'timeForConfirmation'  => 'int',
                ],

                ORM\SchemaInterface::TYPECAST_HANDLER => [
                    ORM\Parser\Typecast::class,
                    Core\ORM\Typecast\PaymentTypeTypecast::class,
                ],
            ],
            'cancellationPolicy' => [
                ORM\SchemaInterface::MAPPER      => ReadOnlyMapper::class, // default POPO mapper
                ORM\SchemaInterface::ENTITY      => CancellationPolicy::class,
                ORM\SchemaInterface::REPOSITORY  => Core\Repository\CancellationPolicyRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => $wpdb->posts,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',

                // property => column
                ORM\SchemaInterface::COLUMNS => [
                    'id'   => 'id',
                    'name' => 'post_title',
                    'description' => 'post_excerpt',
                ],

                ORM\SchemaInterface::TYPECAST => [
                    'id' => 'int',
                ],

                ORM\SchemaInterface::TYPECAST_HANDLER => [
                    ORM\Parser\Typecast::class,
                    Core\ORM\Typecast\CancellationPolicyTypecast::class,
//                    Core\ORM\Typecast\WPEntityTypecast::class,
                ],
            ],
            'customer' => [
                ORM\SchemaInterface::MAPPER      => ORM\Mapper\Mapper::class, // default
                ORM\SchemaInterface::ENTITY      => Core\Model\Customer\Customer::class,
                ORM\SchemaInterface::REPOSITORY  => Core\Repository\CustomerRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => Core\ORM\Schema\CustomerSchema::TABLE_NAME,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',
                ORM\SchemaInterface::COLUMNS     => [
                    'id'         => 'id',
                    'firstName'  => 'first_name',
                    'lastName'   => 'last_name',
                    'email'      => 'email',
                    'phone'      => 'phone',
                    'metadata'   => 'metadata',
                    'createdAt'  => 'created_at',
                    'updatedAt'  => 'updated_at',
                ],

                ORM\SchemaInterface::TYPECAST => [
                    'id'        => 'int',
                    'createdAt' => 'datetime',
                    'updatedAt' => 'datetime',
                    'metadata'  => 'array',
                ],

                ORM\SchemaInterface::TYPECAST_HANDLER => [
                    ORM\Parser\Typecast::class,
                    Core\ORM\Typecast\CustomerTypecast::class,
                ],

                ORM\SchemaInterface::RELATIONS => [],
            ],
            'reservation' => [
                ORM\SchemaInterface::MAPPER      => ORM\Mapper\Mapper::class, // default
                ORM\SchemaInterface::ENTITY      => Core\Model\Reservation\Reservation::class,
                ORM\SchemaInterface::REPOSITORY  => Core\Repository\ReservationRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => Core\ORM\Schema\ReservationSchema::TABLE_NAME,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',
                ORM\SchemaInterface::COLUMNS     => [
                    'id'                   => 'id',
                    'sid'                  => 'sid',
                    'status'               => 'status',
                    'currency'             => 'currency',
                    'language'             => 'language',
                    'checkInDate'          => 'check_in_date',
                    'checkOutDate'         => 'check_out_date',
                    'checkInTime'          => 'check_in_time',
                    'checkOutTime'         => 'check_out_time',
                    'originSourceCode'     => 'origin_source_code',
                    'number'               => 'number',
                    'specialRequest'      => 'special_request',
                    'cancellationCode'     => 'cancellation_code',
                    'groupId'              => 'group_id',
                    'customerId'           => 'customer_id',
                    'cancellationPolicyId' => 'cancellation_policy_id',
                    'paymentTypeId'        => 'payment_type_id',
                    'totalAmount'          => 'total_amount',
                    'waitingPaymentUntil'  => 'waiting_payment_until',
                    'cancelledBy'          => 'cancelled_by',
                    'cancelledAt'          => 'cancelled_at',
                    'cancellationReason'   => 'cancellation_reason',
                    'createdAt'            => 'created_at',
                    'updatedAt'            => 'updated_at',
                ],

                ORM\SchemaInterface::TYPECAST => [
                    'id'                  => 'int',
                    'sid'                 => 'string',
                    'waitingPaymentUntil' => 'datetime',
                    'createdAt'           => 'datetime',
                    'updatedAt'           => 'datetime',
                    'checkInDate'         => 'datetime',
                    'checkOutDate'        => 'datetime',
                    'checkInTime'         => 'string',
                    'checkOutTime'        => 'string',
                    'status'              => 'string',
                    'totalAmount'         => 'int',
                    'cancellationCode'    => 'string',
                    'cancelledAt'         => 'datetime',
                ],

                ORM\SchemaInterface::TYPECAST_HANDLER => [
                    ORM\Parser\Typecast::class,
                    Core\ORM\Typecast\ReservationTypecast::class,
                ],

                ORM\SchemaInterface::RELATIONS => [
                    'customer' => [
                        ORM\Relation::TYPE   => ORM\Relation::BELONGS_TO,
                        ORM\Relation::TARGET => Customer::class,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => true,
                            ORM\Relation::INNER_KEY => ['customerId'],
                            ORM\Relation::OUTER_KEY => ['id'],
                        ],
                    ],
                    'group' => [
                        ORM\Relation::TYPE   => ORM\Relation::BELONGS_TO,
                        ORM\Relation::TARGET => Core\Model\Reservation\GroupReservation::class,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => true,
                            ORM\Relation::NULLABLE  => true,
                            ORM\Relation::INNER_KEY => ['groupId'],
                            ORM\Relation::OUTER_KEY => ['id'],
                        ],
                    ],
                    'cancellationPolicy' => [
                        ORM\Relation::TYPE   => ORM\Relation::BELONGS_TO,
                        ORM\Relation::TARGET => CancellationPolicy::class,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => false,
                            ORM\Relation::NULLABLE  => true,
                            ORM\Relation::INNER_KEY => ['cancellationPolicyId'],
                            ORM\Relation::OUTER_KEY => ['id'],
                        ],
                    ],
                    'paymentType' => [
                        ORM\Relation::TYPE   => ORM\Relation::BELONGS_TO,
                        ORM\Relation::TARGET => PaymentType::class,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => false,
                            ORM\Relation::NULLABLE  => true,
                            ORM\Relation::INNER_KEY => ['paymentTypeId'],
                            ORM\Relation::OUTER_KEY => ['id'],
                        ],
                    ],
                    'accommodationItems' => [
                        ORM\Relation::TYPE   => ORM\Relation::HAS_MANY,
                        ORM\Relation::TARGET => Core\Model\Reservation\ReservationAccommodationItem::class,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => true,
                            ORM\Relation::INNER_KEY => ['id'],
                            ORM\Relation::OUTER_KEY => ['reservationId'],
                        ],
                    ],
                    'extraItems' => [
                        ORM\Relation::TYPE   => ORM\Relation::HAS_MANY,
                        ORM\Relation::TARGET => Core\Model\Reservation\ReservationExtraItem::class,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => true,
                            ORM\Relation::INNER_KEY => ['id'],
                            ORM\Relation::OUTER_KEY => ['reservationId'],
                        ],
                    ],
                    'adjustments' => [
                        ORM\Relation::TYPE   => ORM\Relation::MORPHED_HAS_MANY,
                        ORM\Relation::TARGET => Adjustment::class,
                        ORM\Relation::LOAD   => ORM\Relation::LOAD_PROMISE,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => true,
                            ORM\Relation::MORPH_KEY => 'adjustableType',
                            ORM\Relation::INNER_KEY => 'id',
                            ORM\Relation::OUTER_KEY => 'adjustableId',
                        ],
                    ],
                    'penalties' => [
                        ORM\Relation::TYPE   => ORM\Relation::HAS_MANY,
                        ORM\Relation::TARGET => Core\Model\Penalty\Penalty::class,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => true, // Delete penalties when reservation is deleted
                            ORM\Relation::INNER_KEY => ['id'],
                            ORM\Relation::OUTER_KEY => ['reservationId'],
                        ],
                    ],
                ],
            ],
            'reservationAccommodationItem' => [
                ORM\SchemaInterface::MAPPER      => ORM\Mapper\Mapper::class, // default
                ORM\SchemaInterface::ENTITY      => Core\Model\Reservation\ReservationAccommodationItem::class,
                ORM\SchemaInterface::REPOSITORY  => Core\Repository\ReservationAccommodationItemRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => Core\ORM\Schema\ReservationAccommodationSchema::TABLE_NAME,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',
                ORM\SchemaInterface::COLUMNS     => [
                    'id'                    => 'id',
                    'date'                  => 'date',
                    'basePrice'             => 'base_price',
                    'totalPrice'            => 'total_price',
                    'currency'              => 'currency',
                    'name'                  => 'name',
                    'adults'                => 'adults',
                    'children'              => 'children',
                    'unit'                  => 'unit',
                    'accommodationTypeCode' => 'accommodation_type_code',
                    'ratePlanCode'          => 'rate_plan_code',
                    'details'               => 'details',
                    'reservationId'         => 'reservation_id',
                    'createdAt'             => 'created_at',
                    'updatedAt'             => 'updated_at',
                ],

                ORM\SchemaInterface::TYPECAST => [
                    'id'        => 'int',
                    'date'      => 'datetime',
                    'details'   => 'json',
                    'basePrice' => 'int',
                    'totalPrice' => 'int',
                    'adults'    => 'int',
                    'children'  => 'json',
                    'createdAt' => 'datetime',
                    'updatedAt' => 'datetime',
                ],

                ORM\SchemaInterface::RELATIONS => [
                    'reservation' => [
                        ORM\Relation::TYPE   => ORM\Relation::BELONGS_TO,
                        ORM\Relation::TARGET => Reservation::class,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => false,
                            ORM\Relation::INNER_KEY => ['reservationId'],
                            ORM\Relation::OUTER_KEY => ['id'],
                        ],
                    ],
                    'adjustments' => [
                        ORM\Relation::TYPE   => ORM\Relation::MORPHED_HAS_MANY,
                        ORM\Relation::TARGET => Adjustment::class,
                        ORM\Relation::LOAD   => ORM\Relation::LOAD_PROMISE,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => true,
                            ORM\Relation::MORPH_KEY => 'adjustableType',
                            ORM\Relation::INNER_KEY => 'id',
                            ORM\Relation::OUTER_KEY => 'adjustableId',
                        ],
                    ],
                ],
            ],
            'reservationExtraItem' => [
                ORM\SchemaInterface::MAPPER      => ORM\Mapper\Mapper::class, // default
                ORM\SchemaInterface::ENTITY      => Core\Model\Reservation\ReservationExtraItem::class,
                ORM\SchemaInterface::REPOSITORY  => Core\Repository\ReservationExtraItemRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => Core\ORM\Schema\ReservationExtraSchema::TABLE_NAME,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',
                ORM\SchemaInterface::COLUMNS     => [
                    'id'            => 'id',
                    'basePrice'     => 'base_price',
                    'totalPrice'    => 'total_price',
                    'quantity'      => 'quantity',
                    'currency'      => 'currency',
                    'neutral'       => 'neutral',
                    'name'          => 'name',
                    'code'          => 'code',
                    'details'       => 'details',
                    'date'          => 'date',
                    'reservationId' => 'reservation_id',
                    'createdAt'     => 'created_at',
                    'updatedAt'     => 'updated_at',
                ],

                ORM\SchemaInterface::TYPECAST => [
                    'id'        => 'int',
                    'basePrice' => 'int',
                    'totalPrice' => 'int',
                    'quantity'  => 'int',
                    'neutral'   => 'bool',
                    'date'      => 'datetime',
                    'details'   => 'json',
                    'createdAt' => 'datetime',
                    'updatedAt' => 'datetime',
                ],

                ORM\SchemaInterface::RELATIONS => [
                    'reservation' => [
                        ORM\Relation::TYPE   => ORM\Relation::BELONGS_TO,
                        ORM\Relation::TARGET => Reservation::class,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => false,
                            ORM\Relation::INNER_KEY => ['reservationId'],
                            ORM\Relation::OUTER_KEY => ['id'],
                        ],
                    ],
                    'adjustments' => [
                        ORM\Relation::TYPE   => ORM\Relation::MORPHED_HAS_MANY,
                        ORM\Relation::TARGET => Adjustment::class,
                        ORM\Relation::LOAD   => ORM\Relation::LOAD_PROMISE,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => true,
                            ORM\Relation::MORPH_KEY => 'adjustableType',
                            ORM\Relation::INNER_KEY => 'id',
                            ORM\Relation::OUTER_KEY => 'adjustableId',
                        ],
                    ],
                ],
            ],
            'adjustment' => [
                ORM\SchemaInterface::MAPPER      => ORM\Mapper\Mapper::class, // default
                ORM\SchemaInterface::ENTITY      => Core\Model\Reservation\Adjustment::class,
                ORM\SchemaInterface::REPOSITORY  => Core\Repository\ReservationAdjustmentRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => Core\ORM\Schema\ReservationAdjustmentSchema::TABLE_NAME,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',
                ORM\SchemaInterface::COLUMNS     => [
                    'id'             => 'id',
                    'name'           => 'name',
                    'code'           => 'code',
                    'source'         => 'source',
                    'amount'         => 'amount',
                    'active'         => 'active',
                    'type'           => 'type',
                    'mode'           => 'mode',
                    'strategy'       => 'strategy',
                    'refundable'     => 'refundable',
                    'adjustableType' => 'adjustable_type',
                    'adjustableId'   => 'adjustable_id',
                    'createdAt'      => 'created_at',
                    'updatedAt'      => 'updated_at',
                ],

                ORM\SchemaInterface::TYPECAST => [
                    'id'         => 'int',
                    'active'     => 'bool',
                    'createdAt'  => 'datetime',
                    'updatedAt'  => 'datetime',
                    'refundable' => 'bool',
                    'type'       => AdjustmentType::class,
                    'mode'       => AdjustmentMode::class,
                    'strategy'   => AdjustmentStrategy::class,
                ],

                ORM\SchemaInterface::RELATIONS => [
                    'adjustable' => [
                        ORM\Relation::TYPE   => ORM\Relation::BELONGS_TO_MORPHED,
                        ORM\Relation::TARGET => Core\Contract\Adjustment\AdjustableInterface::class,
                        ORM\Relation::LOAD   => ORM\Relation::LOAD_PROMISE,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::MORPH_KEY => 'adjustableType',
                            ORM\Relation::INNER_KEY => 'adjustableId',
                            ORM\Relation::OUTER_KEY => 'id',
                        ],
                    ],
                ],
            ],
            'reservationGroup' => [
                ORM\SchemaInterface::MAPPER      => ORM\Mapper\Mapper::class, // default
                ORM\SchemaInterface::ENTITY      => Core\Model\Reservation\GroupReservation::class,
                ORM\SchemaInterface::REPOSITORY  => Core\Repository\ReservationGroupRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => Core\ORM\Schema\ReservationGroupSchema::TABLE_NAME,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',
                ORM\SchemaInterface::COLUMNS     => [
                    'id'        => 'id',
                    'status'    => 'status',
                    'currency'  => 'currency',
                    'createdAt' => 'created_at',
                    'updatedAt' => 'updated_at',
                ],

                ORM\SchemaInterface::TYPECAST => [
                    'id'        => 'int',
                    'createdAt' => 'datetime',
                    'updatedAt' => 'datetime',
                    'status'    => 'string'
                ],

                ORM\SchemaInterface::TYPECAST_HANDLER => [
                    ORM\Parser\Typecast::class,
                    Core\ORM\Typecast\ReservationGroupTypecast::class,
                ],

                ORM\SchemaInterface::RELATIONS => [
                    'reservations' => [
                        ORM\Relation::TYPE   => ORM\Relation::HAS_MANY,
                        ORM\Relation::TARGET => Reservation::class,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => true,
                            ORM\Relation::NULLABLE  => true,
                            ORM\Relation::INNER_KEY => ['id'],
                            ORM\Relation::OUTER_KEY => ['groupId'],
                        ],
                    ],
                    'adjustments' => [
                        ORM\Relation::TYPE   => ORM\Relation::MORPHED_HAS_MANY,
                        ORM\Relation::TARGET => Adjustment::class,
                        ORM\Relation::LOAD   => ORM\Relation::LOAD_PROMISE,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => true,
                            ORM\Relation::MORPH_KEY => 'adjustableType',
                            ORM\Relation::INNER_KEY => 'id',
                            ORM\Relation::OUTER_KEY => 'adjustableId',
                        ],
                    ],
                ],
            ],
            'dateUnit' => [
                ORM\SchemaInterface::MAPPER      => ORM\Mapper\Mapper::class, // default
                ORM\SchemaInterface::ENTITY      => Core\Model\DateUnit\DateUnit::class,
                ORM\SchemaInterface::REPOSITORY  => Core\Repository\DateUnitRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => DateUnitSchema::TABLE_NAME,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',
                ORM\SchemaInterface::COLUMNS     => [
                    'id'        => 'id',
                    'ratePlanId' => 'rate_plan_id',
                    'accommodationTypeId'  => 'accommodation_type_id',
                    'date'     => 'date',
                    'price'     => 'price',
                    'stopSale' => 'stop_sale',
                    'minLengthOfStay' => 'min_los',
                    'maxLengthOfStay' => 'max_los',
                    'minLengthOfStayArrival' => 'min_los_arrival',
                    'maxLengthOfStayArrival' => 'max_los_arrival',
                    'minAdvanceBooking' => 'min_adv_booking',
                    'maxAdvanceBooking' => 'max_adv_booking',
                    'closeToArrival' => 'cta',
                    'closeToDeparture' => 'ctd',
                    'createdAt' => 'created_at',
                    'updatedAt' => 'updated_at',
                ],

                ORM\SchemaInterface::TYPECAST => [
                    'id'        => 'int',
                    'ratePlanId' => 'int',
                    'accommodationTypeId'  => 'int',
                    'date'     => 'datetime',
                    'stopSale' => 'bool',
                    'minLengthOfStay' => 'int',
                    'maxLengthOfStay' => 'int',
                    'minLengthOfStayArrival' => 'int',
                    'maxLengthOfStayArrival' => 'int',
                    'minAdvanceBooking' => 'int',
                    'maxAdvanceBooking' => 'int',
                    'closeToArrival' => 'bool',
                    'closeToDeparture' => 'bool',
                    'createdAt' => 'datetime',
                    'updatedAt' => 'datetime',
                ],

                ORM\SchemaInterface::TYPECAST_HANDLER => [
                    ORM\Parser\Typecast::class,
                    Core\ORM\Typecast\DateUnitTypecast::class,
                ],

                ORM\SchemaInterface::RELATIONS => [],
            ],
            'penalty' => [
                // Mapper configuration
                ORM\SchemaInterface::MAPPER      => ORM\Mapper\Mapper::class,
                ORM\SchemaInterface::ENTITY      => Core\Model\Penalty\Penalty::class,
                ORM\SchemaInterface::REPOSITORY  => Core\Repository\PenaltyRepository::class,
                ORM\SchemaInterface::DATABASE    => 'default',
                ORM\SchemaInterface::TABLE       => Core\ORM\Schema\PenaltySchema::TABLE_NAME,
                ORM\SchemaInterface::PRIMARY_KEY => 'id',

                // Column mapping: property => column
                ORM\SchemaInterface::COLUMNS => [
                    'id'               => 'id',
                    'amount'           => 'amount',
                    'currency'         => 'currency',
                    'description'      => 'description',
                    'status'           => 'status',
                    'appliedAt'        => 'applied_at',
                    'comment'          => 'comment',
                    'reservationId'    => 'reservation_id',
                    'createdAt'        => 'created_at',
                    'updatedAt'        => 'updated_at',
                ],

                // Type casting configuration
                ORM\SchemaInterface::TYPECAST => [
                    'id'               => 'int',
                    'amount'           => 'int', // Will be converted to Money by typecast handler
                    'currency'         => 'string',
                    'description'      => 'string',
                    'status'           => 'string', // Will be converted to PenaltyStatus by typecast handler
                    'appliedAt'        => 'datetime',
                    'comment'          => 'string',
                    'reservationId'    => 'int',
                    'createdAt'        => 'datetime',
                    'updatedAt'        => 'datetime',
                ],

                // Typecast handlers
                ORM\SchemaInterface::TYPECAST_HANDLER => [
                    ORM\Parser\Typecast::class,
                    Core\ORM\Typecast\PenaltyTypecast::class,
                ],

                // Relations configuration
                ORM\SchemaInterface::RELATIONS => [
                    'reservation' => [
                        ORM\Relation::TYPE   => ORM\Relation::BELONGS_TO,
                        ORM\Relation::TARGET => Core\Model\Reservation\Reservation::class,
                        ORM\Relation::SCHEMA => [
                            ORM\Relation::CASCADE   => false, // Don't cascade deletes from penalty to reservation
                            ORM\Relation::NULLABLE  => false, // Penalty must have a reservation
                            ORM\Relation::INNER_KEY => ['reservationId'],
                            ORM\Relation::OUTER_KEY => ['id'],
                        ],
                    ],
                ],
            ],
        ];
    }
}
