<?php

declare(strict_types=1);

namespace BookiFlex\Extensions\NotificationPreview\Repository;

use BookiFlex\Core\Contract\Adjustment\AdjustmentMode;
use BookiFlex\Core\Contract\Adjustment\AdjustmentStrategy;
use BookiFlex\Core\Contract\Adjustment\AdjustmentType;
use BookiFlex\Core\Contract\CancellationPolicy\CancellationPolicyTypeInterface;
use BookiFlex\Core\Contract\Reservation\ReservationRepositoryInterface;
use BookiFlex\Core\Model\CancellationPolicy\CancellationPolicy;
use BookiFlex\Core\Model\CancellationPolicy\CancellationRule;
use BookiFlex\Core\Model\Customer\Customer;
use BookiFlex\Core\Model\PaymentType\PaymentType;
use BookiFlex\Core\Model\PaymentType\PaymentTypeInterface;
use BookiFlex\Core\Model\Reservation\Adjustment;
use BookiFlex\Core\Model\Reservation\Reservation;
use BookiFlex\Core\Model\Reservation\ReservationAccommodationItem;
use BookiFlex\Core\Service\NumberGenerator\NumberGenerator;
use Brick\Money\Money;

defined( 'ABSPATH' ) || exit;

class FakeReservationRepository implements ReservationRepositoryInterface
{
    public function findAll(array $scope = []): iterable
    {
        return [$this->getReservation()];
    }

    public function findByPK(mixed $id): ?object
    {
        return $this->getReservation();
    }

    public function findOne(array $scope = []): ?object
    {
        return $this->getReservation();
    }

    private function getReservation(): Reservation
    {
        $reservationNumberGenerator = new NumberGenerator();
        $reservation                = new Reservation(
            '123-456',
            $reservationNumberGenerator->nextNumber(),
            'USD',
            '14:00',
            '11:00',
            'test',
            $this->getAccommodationItems(),
            $this->getCustomer(),
            $this->getCancellationPolicy(),
        );

        $reservation->setId(1);
        $reservation->setPaymentType($this->getPaymentType());
        $reservation->setSpecialRequest("It's a test customer request.");
        $this->applyTaxes($reservation);

        return $reservation;
    }

    private function getAccommodationItems(): array
    {
        $firstDay  = (new \DateTimeImmutable())->add(new \DateInterval('P1D'));
        $secondDay = $firstDay->add(new \DateInterval('P1D'));

        $result   = [];
        $result[] = new ReservationAccommodationItem(
            'Standard Aurora Room (Base)',
            Money::ofMinor(10000, 'USD'),
            $firstDay,
            'AUR',
            'BSD',
            2,
            [],
            json_decode('[{"placementType":"adultOnMainPlace","variant":"__2","quantity":2,"price":10000,"total":10000}]', true),
        );

        $result[] = new ReservationAccommodationItem(
            'Standard Aurora Room (Base)',
            Money::ofMinor(8000, 'USD'),
            $secondDay,
            'AUR',
            'BSD',
            2,
            [],
            json_decode('[{"placementType":"adultOnMainPlace","variant":"__2","quantity":2,"price":8000,"total":8000}]', true),
        );

        return $result;
    }

    private function getCustomer(): Customer
    {
        $customer = new Customer(
            'John',
            'Doe',
            'john@doe.com',
            '+1 (999) 890-890-00'
        );
        $customer->setId(1);

        return $customer;
    }

    private function getCancellationPolicy(): CancellationPolicy
    {
        $cancellationPolicy = new CancellationPolicy(
            'Free cancellation till 72 hours',
            'Free cancellation is available until 72 hours before check-in. After that, first night penalty applies.',
            [new CancellationRule(
                type: CancellationPolicyTypeInterface::PENALTY_AMOUNT_FIRST_NIGHT,
                minHoursUntilStart: 72.0,
                maxHoursUntilStart: null,
                penaltyPercentage: null,
                fixedPenalty: null,
                penaltyInFirstNights: 1
            )],
            true
        );
        $cancellationPolicy->setId(1);

        return $cancellationPolicy;
    }

    private function getPaymentType(): PaymentType
    {
        $paymentType = new PaymentType(
            'On arrival',
            PaymentTypeInterface::PAYMENT_ON_ARRIVAL_TYPE,
            'You will pay after arrival',
            PaymentTypeInterface::AMOUNT_PREPAYMENT_TYPE,
            0,
            PaymentTypeInterface::ABA_DAYS_PERIOD,
            PaymentTypeInterface::ABA_GTE_TYPE,
            0,
            0,
            false,
            true,
            'offline',
            24
        );

        $paymentType->setId(1);
        return $paymentType;
    }

    private function applyTaxes(Reservation $reservation): void
    {
        $vat = new Adjustment(
            'Vat',
            'vat',
            10.0,
            AdjustmentType::Tax,
            AdjustmentStrategy::Inclusive,
            AdjustmentMode::Percentage,
            'taxation.tax_calculator',
            false,
            true
        );

        $city = new Adjustment(
            'City tax',
            'city',
            5.2,
            AdjustmentType::Charge,
            AdjustmentStrategy::Inclusive,
            AdjustmentMode::Fixed,
            'taxation.tax_calculator',
            true,
            true
        );

        $reservation->addAdjustment($city);
        foreach ($reservation->getAccommodationItems() as $item) {
            $item->addAdjustment($vat);
        }
    }

    public function getOccupancyOnDates(\DateTimeImmutable $checkIn, \DateTimeImmutable $checkOut): array
    {
        return [];
    }
}