<?php

namespace Opentalent\OtCore\Tests\Unit\Domain;

use AssertionError;
use Nimut\TestingFramework\TestCase\UnitTestCase;
use Opentalent\OtCore\Domain\Model\Event;
use Opentalent\OtCore\Domain\Model\Organization;

class EventTest extends UnitTestCase
{
    /**
     * Object should instantiate correctly, and properties
     * set with setters should be retrieved by getters
     *
     * @test
     */
    public function canInstantiate() {
        $event = new Event();

        $event->setId(1);
        $event->setType('PortailEvent');
        $event->setOrganizationId(2);
        $event->setSubdomain('subdomain');
        $event->setName('name');
        $event->setDescription('description');
        $event->setCategories(['categorie']);
        $event->setUrl('www.url.com');
        $event->setRule('rule');
        $event->setDatetimeStart(new \DateTime('2021-01-01'));
        $event->setDatetimeEnd(new \DateTime('2121-01-01'));
        $event->setDates('dates');
        $event->setPlacename('placename');
        $event->setPlaceDescription('place description');
        $event->setPlaceFloorSize('floor size');
        $event->setPlaceCapacity('place capacity');
        $event->setCity('casablanca');
        $event->setPostalCode('00000');
        $event->setStreetAddress('adress');
        $event->setLongitude(1.23456);
        $event->setLatitude(1.23456);
        $event->setRoomName('room');
        $event->setRoomDescription('room description');
        $event->setRoomLocalisation('room localization');
        $event->setRoomCapacity('room capacity');
        $event->setRoomFloorSize('room floorsize');
        $event->setZupId(3);
        $event->setDeepLink('deeplink');
        $event->setImage('logo.svg');
        $event->setPriceMini(10.50);
        $event->setMeetingSchedule(['meeting']);
        $event->setApi(true);
        $event->setParentName('parent');
        $event->setParentSubdomain('parent.org');

        $organization = new Organization();
        $event->setOrganization($organization);

        $this->assertEquals(1, $event->getId());
        $this->assertEquals('PortailEvent', $event->getType());
        $this->assertEquals(2, $event->getOrganizationId());
        $this->assertEquals('subdomain', $event->getSubdomain());
        $this->assertEquals('name', $event->getName());
        $this->assertEquals('description', $event->getDescription());
        $this->assertEquals(['categorie'], $event->getCategories());
        $this->assertEquals('www.url.com', $event->getUrl());
        $this->assertEquals('rule', $event->getRule());
        $this->assertEquals(new \DateTime('2021-01-01'), $event->getDatetimeStart());
        $this->assertEquals(new \DateTime('2121-01-01'), $event->getDatetimeEnd());
        $this->assertEquals('dates', $event->getDates());
        $this->assertEquals('placename', $event->getPlacename());
        $this->assertEquals('place description', $event->getPlaceDescription());
        $this->assertEquals('floor size', $event->getPlaceFloorSize());
        $this->assertEquals('place capacity', $event->getPlaceCapacity());
        $this->assertEquals('casablanca', $event->getCity());
        $this->assertEquals('00000', $event->getPostalCode());
        $this->assertEquals('adress', $event->getStreetAddress());
        $this->assertEquals(1.23456, $event->getLongitude());
        $this->assertEquals(1.23456, $event->getLatitude());
        $this->assertEquals('room', $event->getRoomName());
        $this->assertEquals('room description', $event->getRoomDescription());
        $this->assertEquals('room localization', $event->getRoomLocalisation());
        $this->assertEquals('room capacity', $event->getRoomCapacity());
        $this->assertEquals('room floorsize', $event->getRoomFloorSize());
        $this->assertEquals(3, $event->getZupId());
        $this->assertEquals('deeplink', $event->getDeepLink());
        $this->assertEquals('logo.svg', $event->getImage());
        $this->assertEquals(10.50, $event->getPriceMini());
        $this->assertEquals(['meeting'], $event->getMeetingSchedule());
        $this->assertEquals(true, $event->getApi());
        $this->assertEquals(true, $event->isApi());
        $this->assertEquals('parent', $event->getParentName());
        $this->assertEquals('parent.org', $event->getParentSubdomain());
        $this->assertEquals($organization, $event->getOrganization());
    }

    /**
     * Nullable fields should be able to be set to null,
     * while non nullable shall raise an exception if set to null
     *
     * @test
     */
    public function nullableOrNot() {

        $event = new Event();

        // non-nullable properties
        try {
            $event->setId(null);
            throw new AssertionError('Event::setId should not accept a null value');
        } catch (\TypeError $e) {}
        try {
            $event->setOrganizationId(null);
            throw new AssertionError('Event::setOrganizationId should not accept a null value');
        } catch (\TypeError $e) {}

        // nullable properties
        $event->setType(null);
        $event->setSubdomain(null);
        $event->setName(null);
        $event->setDescription(null);
        $event->setCategories(null);
        $event->setUrl(null);
        $event->setRule(null);
        $event->setDatetimeStart(null);
        $event->setDatetimeEnd(null);
        $event->setDates(null);
        $event->setPlacename(null);
        $event->setPlaceDescription(null);
        $event->setPlaceFloorSize(null);
        $event->setPlaceCapacity(null);
        $event->setCity(null);
        $event->setPostalCode(null);
        $event->setStreetAddress(null);
        $event->setLongitude(null);
        $event->setLatitude(null);
        $event->setRoomName(null);
        $event->setRoomDescription(null);
        $event->setRoomLocalisation(null);
        $event->setRoomCapacity(null);
        $event->setRoomFloorSize(null);
        $event->setZupId(null);
        $event->setDeepLink(null);
        $event->setImage(null);
        $event->setPriceMini(null);
        $event->setMeetingSchedule(null);
        $event->setApi(null);
        $event->setParentName(null);
        $event->setParentSubdomain(null);

        // Just to avoid this test to be considered as risky
        $this->assertEquals(1, 1);
    }

    /**
     * getFormattedDates() should format a correct sentence when
     * the start date and the end date are on two different days
     *
     * @test
     */
    public function getFormattedDatesOnDifferentDays()
    {
        $event = new Event();
        $event->setDatetimeStart(new \DateTime('2021-01-01 09:00'));
        $event->setDatetimeEnd(new \DateTime('2021-01-31 18:00'));
        $this->assertEquals("Du 01/01/2021 09h00 au 31/01/2021 18h00", $event->getFormattedDates());
    }

    /**
     * getFormattedDates should format a correct sentence when
     * the start date and the end date are on the same day
     *
     * @test
     */
    public function getFormattedDatesOnSameDay()
    {
        $event = new Event();
        $event->setDatetimeStart(new \DateTime('2021-01-01 09:00'));
        $event->setDatetimeEnd(new \DateTime('2021-01-01 18:00'));
        $this->assertEquals("Le 01/01/2021 de 09h00 à 18h00", $event->getFormattedDates());
    }

    /**
     * getFormattedDates should format a correct sentence when
     * no end date has been provided
     *
     * @test
     */
    public function getFormattedDatesWithStartDateOnly()
    {
        $event = new Event();
        $event->setDatetimeStart(new \DateTime('2021-01-01 09:00'));
        $this->assertEquals("A partir du 01/01/2021 09h00", $event->getFormattedDates());
    }

    /**
     * getFormattedDates should format a correct sentence when
     * no start date has been provided
     *
     * @test
     */
    public function getFormattedDatesWithEndDateOnly()
    {
        $event = new Event();
        $event->setDatetimeEnd(new \DateTime('2021-01-31 18:00'));
        $this->assertEquals("Jusqu'au 31/01/2021 18h00", $event->getFormattedDates());
    }

    /**
     * getFormattedDates should return an empty sentence when
     * no date has been provided
     *
     * @test
     */
    public function getFormattedDatesWithNoDates()
    {
        $event = new Event();
        $this->assertEquals("", $event->getFormattedDates());
    }

    /**
     * getLocAndDate should return the placename, city and the formatted dates
     * of the events, regarding which informations are available
     *
     * @test
     */
    public function getLocAndDateWithFullInformations() {
        $event = new Event();
        $event->setPlacename("Place");
        $event->setCity("City");
        $event->setDatetimeStart(new \DateTime('2021-01-01 09:00'));
        $event->setDatetimeEnd(new \DateTime('2021-01-01 18:00'));
        $this->assertEquals("Place (City), le 01/01/2021 de 09h00 à 18h00", $event->getLocAndDate());
    }

    /**
     * getLocAndDate should return the placename, city and the formatted dates
     * of the events, regarding which informations are available
     *
     * @test
     */
    public function getLocAndDateWithPlaceAndCity() {
        $event = new Event();
        $event->setPlacename("Place");
        $event->setCity("City");
        $this->assertEquals("Place (City)", $event->getLocAndDate());
    }

    /**
     * getLocAndDate should return the placename, city and the formatted dates
     * of the events, regarding which informations are available
     *
     * @test
     */
    public function getLocAndDateWithOnlyPlace() {
        $event = new Event();
        $event->setPlacename("Place");
        $this->assertEquals("Place", $event->getLocAndDate());
    }

    /**
     * getLocAndDate should return the placename, city and the formatted dates
     * of the events, regarding which informations are available
     *
     * @test
     */
    public function getLocAndDateWithOnlyCity() {
        $event = new Event();
        $event->setCity("City");
        $this->assertEquals("City", $event->getLocAndDate());
    }

    /**
     * getFullAdress should return a concateneted address of the event,
     * regarding which informations are available
     *
     * @test
     */
    public function getFullAddress() {
        $event = new Event();
        $event->setPlacename("Place");
        $event->setRoomName("room");
        $event->setRoomLocalisation("loc");
        $event->setStreetAddress("street");
        $event->setCity("City");
        $event->setPostalCode("00000");

        $this->assertEquals(
            "Place\nroom\nloc\nstreet\n00000 City",
            $event->getFullAddress()
        );
    }

    /**
     * getInfosTable should return an array holding the informations of the event,
     * regarding which informations are available
     *
     * @test
     */
    public function getInfosTable() {
        $event = new Event();
        $event->setPlacename("Place");
        $event->setPlaceDescription("description");
        $event->setCity("City");
        $event->setUrl("event.com");

        $this->assertEquals(
            [
                'Lieu' => 'Place',
                'Description du lieu' => 'description',
                'Adresse' => "Place\nCity",
                'Lien externe' => 'event.com',
            ],
            $event->getInfosTable()
        );
    }

    /**
     * getShortDescription should return an eluded description
     * if the description is longer than 100 cars
     *
     * @test
     */
    public function getShortDescriptionWithLongDescription()
    {

        $long_description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " .
        "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut  " .
        "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore " .
        "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " .
        "mollit anim id est laborum.";

        $event = new Event();
        $event->setDescription($long_description);

        $this->assertEquals(
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore...",
            $event->getShortDescription()
        );
    }

    /**
     * getShortDescription should return the actual description
     * if the description is shorter than 100 cars
     *
     * @test
     */
    public function getShortDescriptionWithShortDescription() {

        $long_description = "Lorem ipsum dolor sit amet";

        $event = new Event();
        $event->setDescription($long_description);

        $this->assertEquals(
            "Lorem ipsum dolor sit amet",
            $event->getShortDescription()
        );
    }

    /**
     * getShortDescription should return an empty string
     * if the description is null or empty
     *
     * @test
     */
    public function getShortDescriptionWithNoDescription() {
        $event = new Event();

        $this->assertEquals(
            "",
            $event->getShortDescription()
        );
    }

    /**
     * getInfosLink should return the url property of the event
     * if this url is valid
     *
     * @test
     */
    public function getInfosLinkWithValidUrl() {
        $event = new Event();
        $url = 'https://structure.org/event?id=1';

        $event->setUrl($url);

        $this->assertEquals(
            $url,
            $event->getInfosLink()
        );
    }

    /**
     * getInfosLink should return the url of the website's organization
     * if this url is invalid
     *
     * @test
     */
    public function getInfosLinkWithInvalidUrl() {
        $event = new Event();
        $url = 'ma structure';

        $event->setUrl($url);
        $event->setSubdomain('sub');

        $this->assertEquals(
            'https://sub.opentalent.fr',
            $event->getInfosLink()
        );
    }

    /**
     * getInfosLink should return the url of the website's organization
     * if this url is invalid
     *
     * @test
     */
    public function getInfosLinkWithNoData() {
        $event = new Event();
        $url = 'ma structure';
        $event->setUrl($url);

        $this->assertEquals(
            '',
            $event->getInfosLink()
        );
    }

}
