<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Tests\Entity;

use Ferienpass\CoreBundle\Entity\BookEntry;
use Ferienpass\CoreBundle\Entity\Debtor;
use Ferienpass\CoreBundle\Entity\Payment;
use Ferienpass\CoreBundle\Entity\User;
use PHPUnit\Framework\TestCase;

final class BookEntryTest extends TestCase
{
    public function testGetValueReturnsValue(): void
    {
        $debtor = new Debtor();
        $entry = new BookEntry(500, $debtor);

        self::assertSame(500, $entry->getValue());
    }

    public function testGetDebtorReturnsDebtor(): void
    {
        $debtor = new Debtor();
        $entry = new BookEntry(100, $debtor);

        self::assertSame($debtor, $entry->getDebtor());
    }

    public function testGetIdIsNullByDefault(): void
    {
        $debtor = new Debtor();
        $entry = new BookEntry(100, $debtor);

        self::assertNull($entry->getId());
    }

    public function testGetBookingDateIsSetOnConstruct(): void
    {
        $debtor = new Debtor();
        $entry = new BookEntry(100, $debtor);

        self::assertInstanceOf(\DateTimeInterface::class, $entry->getBookingDate());
    }

    public function testDefaultTypeIsManualWhenNoPayment(): void
    {
        $debtor = new Debtor();
        $entry = new BookEntry(100, $debtor);

        self::assertSame('manual', $entry->getType());
    }

    public function testTypeIsPaymentWhenPaymentProvided(): void
    {
        // We can't easily construct a Payment without DB, so test the type logic
        // via the constructor directly. The type defaults to 'payment' when payment is given.
        // Let's use reflection to test with a mock payment.
        $debtor = new Debtor();
        $entry = new BookEntry(100, $debtor, type: 'payment');

        self::assertSame('payment', $entry->getType());
    }

    public function testConstructorThrowsForInvalidType(): void
    {
        $debtor = new Debtor();

        $this->expectException(\InvalidArgumentException::class);
        new BookEntry(100, $debtor, type: 'invalid_type');
    }

    public function testGetPostingRecordReturnsEmptyStringByDefault(): void
    {
        $debtor = new Debtor();
        $entry = new BookEntry(100, $debtor);

        self::assertSame('', $entry->getPostingRecord());
    }

    public function testGetPostingRecordReturnsProvidedValue(): void
    {
        $debtor = new Debtor();
        $entry = new BookEntry(100, $debtor, postingRecord: 'Journal Entry #1');

        self::assertSame('Journal Entry #1', $entry->getPostingRecord());
    }

    public function testTypeDefaultsToPaymentWhenPaymentProvided(): void
    {
        $user = new User();
        $debtor = new Debtor($user);
        $payment = new Payment($debtor);

        $entry = new BookEntry(100, $debtor, $payment);

        self::assertSame('payment', $entry->getType());
        self::assertTrue($entry->isPayment());
    }

    public function testGetPaymentReturnsProvidedPayment(): void
    {
        $user = new User();
        $debtor = new Debtor($user);
        $payment = new Payment($debtor);

        $entry = new BookEntry(100, $debtor, $payment);

        self::assertSame($payment, $entry->getPayment());
    }

    public function testGetPaymentIsNullWhenNoPayment(): void
    {
        $debtor = new Debtor();
        $entry = new BookEntry(100, $debtor);

        self::assertNull($entry->getPayment());
    }

    public function testIsPaymentFalseForManualEntry(): void
    {
        $debtor = new Debtor();
        $entry = new BookEntry(100, $debtor);

        self::assertFalse($entry->isPayment());
    }
}
