<?php
namespace models;

use library\Slugger;
use observers\TaggingObserver;
/**
 * Page model class
 * @author Jérôme Brilland
 * @version 2.1
 * @copyright (c) 2018-2022, Jérôme Brilland
 * @license http://www.gnu.org/licenses/gpl.txt GNU General Public License
 */
class Page extends \ActiveRecord {

    use Slugger;

    const DRAFT = 0;
    const PUBLISHED = 1;
    const HIDDEN = 2;

    protected function initialize() {
        $this->attach( new \NullifyBlankObserver() );
        $this->attach( new TaggingObserver() );

        if ( !isset( $this->publication_date ) ) {
            $this->publication_date = date( 'Y-m-d' );
        }
        if ( !isset( $this->publication_time ) ) {
            $this->publication_time = date( 'H:i:s' );
        }
    }

    protected function validate() {
        $i18n = \IoC::resolve( 'i18n' );
        $this->validateMaxLength( 'title', 100, $i18n->__( 'too_long_title', 100 ) );
        $this->validateNotEmpty( 'title', $i18n->__( 'title_cannot_be_empty' ) );
        $this->validateMaxLength( 'description', 255, $i18n->__( 'too_long_description', 255 ) );
        $this->validateMaxLength( 'language', 2, $i18n->__( 'too_long_language', 2 ) );
        $this->validateMaxLength( 'slug', 100, $i18n->__( 'too_long_slug', 100 ) );
        $this->validateNotEmpty( 'content', $i18n->__( 'content_cannot_be_empty' ) );
        $this->validateNotEmpty( 'template_id', $i18n->__( 'template_is_required' ) );
        $this->validateInArray( 'status', [self::DRAFT, self::PUBLISHED, self::HIDDEN], $i18n->__( 'invalid_status' ) );
        $this->validateInteger( 'position', $i18n->__( 'not_an_integer' ) );
        $this->validateDate( 'publication_date', $i18n->__( 'invalid_publication_date' ) );
        $this->validateNotEmpty( 'publication_date', $i18n->__( 'publication_date_is_required' ) );
        $this->validateTime( 'publication_time', $i18n->__( 'invalid_publication_time' ) );
        $this->validateNotEmpty( 'publication_time', $i18n->__( 'publication_time_is_required' ) );
        $this->validateDate( 'expiration_date', $i18n->__( 'invalid_expiration_date' ) );
        if ( !empty( $this->expiration_date ) ) {
            $this->validateNotEmpty( 'expiration_time', $i18n->__( 'expiration_time_is_required') );
            
            $publicationDate = new \DateTimeImmutable( $this->publication_date . ' ' . $this->publication_time );
            $expirationDate = new \DateTimeImmutable( $this->expiration_date . ' ' . $this->expiration_time );
            if ( $expirationDate <= $publicationDate ) {
                $this->addError( 'expiration_date', $i18n->__( 'expiration_after_publication' ) );
            }
        }
        if ( $this->isNewRecord() || $this->isAttributeChanged( 'slug' ) ) {
            $this->validateUnique( 'slug', $i18n->__( 'slug_already_exists' ) );
        }
    }

    protected function beforeValidate() {
        $this->title = trim( $this->title );
        if ( empty( $this->slug ) ) {
            $this->slug = $this->slugify( $this->title );
        } else {
            $this->slug = trim( $this->slug );
            $this->slug = strtolower( $this->slug );
        }
    }

    public function isPublished() {
        $now = new \DateTimeImmutable();
        $publicationDate = new \DateTimeImmutable( $this->publication_date . ' ' . $this->publication_time );
        $expirationDate = ( !empty( $this->expiration_date ) ) ? new \DateTimeImmutable( $this->expiration_date . ' ' . $this->expiration_time ) : null;
        return ( self::PUBLISHED == $this->status ) && ( $publicationDate <= $now ) && ( empty( $expirationDate ) || ( $expirationDate > $now ) );
    }

    protected function getParent() {
        return Page::findOne( ['page_id', 'title', 'parent_id'], ['page_id' => $this->parent_id] );
    }

    protected function getChildren() {
        return Page::findMany( ['page_id', 'title', 'parent_id'], ['parent_id' => $this->page_id] );
    }

    public static function findLastModifiedPages( $limit = 5 ) {
        return Page::findMany( ['page_id', 'title', 'updated_at'], ['LIMIT'=> $limit, 'ORDER' => ['updated_at' => 'DESC']] );
    }

    public static function findLastCreatedPages( $limit = 5 ) {
        return Page::findMany( ['page_id', 'title', 'created_at'], ['LIMIT'=> $limit, 'ORDER' => ['created_at' => 'DESC']] );
    }

    public static function findPublishedPage( $idOrSlug ) {
        $where = ['status' => Page::PUBLISHED,
            'OR #first' => ['publication_date[<]' => date( 'Y-m-d' ),
                'AND' => ['publication_date' => date( 'Y-m-d' ), 'publication_time[<=]' => date( 'H:i:s' )]],
            'OR #second' => ['expiration_date' => null,
                'expiration_date[>]' => date( 'Y-m-d' ),
                'AND' => ['expiration_date' => date( 'Y-m-d' ), 'expiration_time[>]' => date( 'H:i:s' )]]];

        if ( is_int( $idOrSlug ) ) {
            $where['page_id'] = $idOrSlug;
        } else {
            $where['slug'] = $idOrSlug;
        }

        $columns = [
            'page.page_id',
            'page.title',
            'page.status',
            'page.description',
            'page.language',
            'page.slug',
            'page.content',
            'page.parent_id',
            'page.publication_date',
            'page.publication_time',
            'page.created_at',
            'page.updated_at',
            'template.name(template_name)'
        ];

        $join = ['[>]template' => 'template_id'];

        return Page::findOne( $join, $columns, $where );
    }

    protected function getPublishedChildren() {
        $columns = [
            'page_id',
            'title',
            'language',
            'slug',
            'publication_date',
            'publication_time'
        ];

        $where = ['parent_id' => $this->page_id,
            'status' => Page::PUBLISHED,
            'OR #first' => ['publication_date[<]' => date( 'Y-m-d' ),
                'AND' => ['publication_date' => date( 'Y-m-d' ), 'publication_time[<=]' => date( 'H:i:s' )]],
            'OR #second' => ['expiration_date' => null,
                'expiration_date[>]' => date( 'Y-m-d' ),
                'AND' => ['expiration_date' => date( 'Y-m-d' ), 'expiration_time[>]' => date( 'H:i:s' )]],
            'ORDER' => 'position'];

        return Page::findMany( $columns, $where );
    }
}
