<?php

namespace Opentalent\OtTemplating\Domain\Repository;

use Exception;
use Opentalent\OtTemplating\Domain\Model\Event;
use Opentalent\OtTemplating\Exception\ApiRequestException;

class EventRepository extends BaseApiRepository
{
    CONST URI = BaseApiRepository::BASE_URI . 'public/events';
    const HYDRA_TYPE = 'PortailEvent';

    /**
     * Returns an Event object from an Api record
     * @param array $record A record as returned by $this->getApiRecords
     * @return Event|null
     * @throws Exception
     */
    private function eventFromJson($record) {
        if ($record->{'@type'} != $this::HYDRA_TYPE) {
            return null;
        }
        $event = new Event();
        $a = explode('/', $record->{'@id'});
        $event->setId(end($a));
        $event->setOrganizationId($record->{'organizationId'});
        $event->setSubdomain($record->{'subDomain'});
        $event->setName($record->{'name'});
        $event->setDescription($record->{'description'});
        $event->setUrl($record->{'url'});
        $event->setRule($record->{'rule'});
        $event->setDatetimeStart(new \DateTime($record->{'datetimeStart'}));
        $event->setDatetimeEnd(new \DateTime($record->{'datetimeEnd'}));
        $event->setDates($record->{'dates'});
        $event->setPlacename($record->{'placeName'});
        $event->setPlaceDescription($record->{'placeDescription'});
        $event->setPlaceFloorSize($record->{'placeFloorSize'});
        $event->setPlaceCapacity($record->{'placeCapacity'});
        $event->setCity($record->{'city'});
        $event->setPostalCode($record->{'postalCode'});
        $event->setStreetAddress($record->{'streetAddress'});
        $event->setLongitude($record->{'longitude'});
        $event->setLatitude($record->{'latitude'});
        $event->setRoomName($record->{'roomName'});
        $event->setRoomDescription($record->{'roomDescription'});
        $event->setRoomLocalisation($record->{'roomLocalisation'});
        $event->setRoomCapacity($record->{'roomCapacity'});
        $event->setRoomFloorSize($record->{'roomFloorSize'});
        $event->setZupId($record->{'zupId'});
        $event->setDeepLink($record->{'deepLink'});
        $event->setImage($record->{'image'});
        $event->setPriceMini($record->{'priceMini'});
        $event->setMeetingSchedule($record->{'meetingSchedule'});
        $event->setApi($record->{'api'});
        $event->setParentName($record->{'parentName'});
        $event->setParentSubdomain($record->{'parentSubDomain'});
        return $event;
    }

    /**
     * Returns an array of Event objects from an array of Api records
     *
     * @param array $records An array of records as returned by $this->getApiRecords
     * @return array
     * @throws Exception
     */
    private function eventsFromJson($records) {
        $events = [];
        foreach ($records as $record) {
            $events[] = $this->eventFromJson($record);
        }
        return $events;
    }

    /**
     * Get the event matching the given id
     *
     * @param int $id The id of the event
     * @return Event         Event
     * @throws ApiRequestException
     * @throws Exception
     */
    public function findById($id) {
        $params = [];
        $record = $this->getApiFirstRecord($this::URI . '/' . $id, $params);
        return $this->eventFromJson($record);
    }

    /**
     * Get the events of the organization
     *
     * @param int $organizationId The id of the organization
     * @param \Datetime $fromDate Only return events with ending date posterior or equal to this date (leave null for disable the filter)
     * @param \Datetime $toDate Only return events with starting date anterior or equal to this date (leave null for disable the filter)
     * @param int $limit Limit the number of results returned (-1 to disable the limitation)
     * @return array Events
     * @throws ApiRequestException
     * @throws Exception
     */
    public function findByOrganizationId(int $organizationId, $fromDate = null, $toDate = null, $limit = -1) {
        $params = [];
        $params['organizationId'] = $organizationId;

        if ($limit > 0) {
            $params['itemsPerPage'] = $limit;
        }
        if ($fromDate !== null) {
            // Inutile a priori: la view de l'API s'en occupe déjà en amont
            $params['filter[where][datetimeEnd][gte]'] = $fromDate->format('c');
        }
        if ($toDate !== null) {
            $params['filter[where][datetimeStart][lte]'] = $toDate->format('c');
        }
        $params['filter[order][0][datetimeEnd]'] = 'ASC';

        $records = $this->getApiRecords($this::URI, $params);
        return $this->eventsFromJson($records);
    }

    /**
     * Get the events of the organization's parents
     *
     * @param int $organizationId The id of the organization
     * @param \Datetime $fromDate Only return events with ending date posterior or equal to this date (leave null for disable the filter)
     * @param \Datetime $toDate Only return events with starting date anterior or equal to this date (leave null for disable the filter)
     * @param int $limit Limit the number of results returned (-1 to disable the limitation)
     * @return array                        Events
     * @throws ApiRequestException
     * @throws Exception
     */
    public function findParentsByOrganizationId(int $organizationId, $fromDate = null, $toDate = null, $limit = -1) {
        $params = [];
        $params['organizationId'] = $organizationId;

        if ($limit > 0) {
            $params['itemsPerPage'] = $limit;
        }
        if ($fromDate !== null) {
            // Inutile a priori: la view de l'API s'en occupe déjà en amont
            $params['filter[where][datetimeEnd][gte]'] = $fromDate->format('c');
        }
        if ($toDate !== null) {
            $params['filter[where][datetimeStart][lte]'] = $toDate->format('c');
        }
        $params['filter[order][0][datetimeStart]'] = 'ASC';

        $params['parent'] = '1';

        $records = $this->getApiRecords($this::URI, $params);
        return $this->eventsFromJson($records);
    }

    /**
     * Get the events of the organization's parents
     *
     * @param int $organizationId The id of the organization
     * @param \Datetime|null $fromDate Only return events with ending date posterior or equal to this date (leave null for disable the filter)
     * @param \Datetime|null $toDate Only return events with starting date anterior or equal to this date (leave null for disable the filter)
     * @param int $limit Limit the number of results returned (-1 to disable the limitation)
     * @return array                        Events
     * @throws ApiRequestException
     * @throws Exception
     */
    public function findChildrenByOrganizationId(int $organizationId, $fromDate = null, $toDate = null, $limit = -1) {
        $params = [];
        $params['organizationId'] = $organizationId;

        if ($limit > 0) {
            $params['itemsPerPage'] = $limit;
        }
        if ($fromDate !== null) {
            // Inutile a priori: la view de l'API s'en occupe déjà en amont
            $params['filter[where][datetimeEnd][gte]'] = $fromDate->format('c');
        }
        if ($toDate !== null) {
            $params['filter[where][datetimeStart][lte]'] = $toDate->format('c');
        }
        $params['filter[order][0][datetimeStart]'] = 'ASC';

        $params['children'] = '1';

        $records = $this->getApiRecords($this::URI, $params);
        return $this->eventsFromJson($records);
    }

    /**
     * Get the events of the organization
     *
     * @param int $organizationId The id of the organization
     * @param array $searchParams Search arguments
     * @return array                        Events
     * @throws ApiRequestException
     * @throws Exception
     */
    public function searchBy(int $organizationId, $searchParams = []) {
        $params = [];
        $params['organizationId'] = $organizationId;
        $params['filter[order][0][datetimeEnd]'] = 'ASC';
        $params = array_merge($params, $searchParams);

        $records = $this->getApiRecords($this::URI, $params);
        return $this->eventsFromJson($records);
    }

}
