<?php

namespace WordpressModels\ORM\Entity;

use DateTimeInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Context;
use Symfony\Component\Serializer\Attribute\Groups;

/**
 * Entity mapping for the WordPress posts table.
 *
 * This entity is a mapped superclass for all post types. New post types should extend this class and can be added to
 * the discriminator map using the `doctrine_post_type_discriminator_map` filter {@see PostTypeClassMetadataListener}.
 *
 * Post types should be inferred from the subclass type, or can be retrieved using the
 * {@see ORM\ClassMetadata::$discriminatorValue} property.
 *
 * Serialization:
 * - read_post: The default serialization group for posts.
 * - read_post_details: The serialization group for posts with more details.
 * - read_post_secure: The serialization group for posts with secure details.
 */
#[
    ORM\Table('posts'),
    ORM\Index(['post_parent'], name: 'post_parent'),
    ORM\Index(['post_name'], name: 'post_name'),
    ORM\Index(['post_author'], name: 'post_author'),
    ORM\Index(['post_type', 'post_status', 'post_date', 'ID'], name: 'type_status_date'),
    ORM\Entity,
    ORM\Cache(usage: 'NONSTRICT_READ_WRITE', region: 'wp_posts')
]
#[
    ORM\MappedSuperclass,
    ORM\InheritanceType('SINGLE_TABLE'),
    ORM\DiscriminatorColumn('post_type', type: Types::STRING, length: 20, options: ['default' => 'post']),
    ORM\DiscriminatorMap(['post' => Post::class])
]
class Post
{
    /**
     * @use GetMetaValueTrait<PostMeta>
     */
    use GetMetaValueTrait;

    #[ORM\Column(name: 'ID', type: Types::BIGINT, options: ['unsigned' => true])]
    #[ORM\Id]
    #[ORM\GeneratedValue(strategy: 'IDENTITY')]
    #[Groups('read_post')]
    protected ?int $id = null;

    #[
        ORM\ManyToOne(targetEntity: User::class, inversedBy: 'posts'),
        ORM\JoinColumn(name: 'post_author', referencedColumnName: 'ID')
    ]
    #[Groups(['read_post_details', 'read_post_assoc', 'read_post_author'])]
    protected User $author;

    #[ORM\Column(name: 'post_date', type: Types::DATETIME_MUTABLE, options: ['default' => '0000-00-00 00:00:00'])]
    #[Groups('read_post')]
    protected DateTimeInterface $date;

    #[ORM\Column(name: 'post_date_gmt', type: Types::DATETIME_MUTABLE, options: ['default' => '0000-00-00 00:00:00'])]
    #[Groups('read_post_details')]
    protected DateTimeInterface $dateGmt;

    #[ORM\Column(name: 'post_content', type: Types::TEXT, length: 0)]
    #[Groups('read_post')]
    protected ?string $content = '';

    #[ORM\Column(name: 'post_title', type: Types::TEXT, length: 65535)]
    #[Groups('read_post')]
    protected ?string $title = '';

    #[ORM\Column(name: 'post_excerpt', type: Types::TEXT, length: 65535)]
    #[Groups('read_post')]
    protected ?string $excerpt = '';

    #[ORM\Column(name: 'post_status', type: Types::STRING, length: 20, options: ['default' => 'publish'])]
    #[Groups('read_post_details')]
    protected string $status = 'publish';

    #[ORM\Column(name: 'comment_status', type: Types::STRING, length: 20, options: ['default' => 'open'])]
    #[Groups('read_post_details')]
    protected string $commentStatus = 'open';

    #[ORM\Column(name: 'ping_status', type: Types::STRING, length: 20, options: ['default' => 'open'])]
    #[Groups('read_post_details')]
    protected string $pingStatus = 'open';

    #[ORM\Column(name: 'post_password', type: Types::STRING, length: 255)]
    #[Groups('read_post_secure')]
    protected string $password = '';

    #[ORM\Column(name: 'post_name', type: Types::STRING, length: 200)]
    #[Groups('read_post')]
    protected string $name = '';

    #[ORM\Column(name: 'to_ping', type: Types::TEXT, length: 65535)]
    #[Groups('read_post_details')]
    protected ?string $toPing = null;

    #[ORM\Column(name: 'pinged', type: Types::TEXT, length: 65535)]
    #[Groups('read_post_details')]
    protected ?string $pinged = null;

    #[ORM\Column(name: 'post_modified', type: Types::DATETIME_MUTABLE, options: ['default' => '0000-00-00 00:00:00'])]
    #[Groups('read_post')]
    protected DateTimeInterface $updatedAt;

    #[ORM\Column(name: 'post_modified_gmt', type: Types::DATETIME_MUTABLE, options: ['default' => '0000-00-00 00:00:00'])]
    #[Groups('read_post_details')]
    protected DateTimeInterface $updatedAtGmt;

    #[ORM\Column(name: 'post_content_filtered', type: Types::TEXT, length: 0)]
    #[Groups('read_post_details')]
    protected ?string $contentFiltered = '';

    #[
        ORM\ManyToOne(targetEntity: Post::class, inversedBy: 'children'),
        ORM\JoinColumn('post_parent', referencedColumnName: 'ID', nullable: true)
    ]
    #[Groups(['read_post_details', 'read_post_assoc', 'read_post_parent'])]
    protected ?Post $parent = null;

    #[ORM\OneToMany(mappedBy: 'parent', targetEntity: Post::class)]
    #[Groups(['read_post_details', 'read_post_assoc', 'read_post_children'])]
    protected Collection $children;

    #[ORM\Column(name: 'guid', type: Types::STRING, length: 255)]
    #[Groups('read_post')]
    protected string $guid = '';

    #[ORM\Column(name: 'menu_order', type: Types::INTEGER)]
    #[Groups('read_post_details')]
    protected int $menuOrder = 0;

    #[ORM\Column(name: 'post_mime_type', type: Types::STRING, length: 100)]
    #[Groups('read_post_details')]
    protected string $mimeType = '';

    #[ORM\Column(name: 'comment_count', type: Types::BIGINT)]
    #[Groups('read_post')]
    protected int $commentCount = 0;

    /**
     * @var Collection<TermRelationship>
     */
    #[ORM\OneToMany(mappedBy: 'object', targetEntity: TermRelationship::class)]
    #[Groups(['read_post_details', 'read_post_assoc', 'read_post_terms'])]
    protected Collection $termRelationships;

    /**
     * @var Collection<PostMeta>
     */
    #[ORM\OneToMany(mappedBy: 'post', targetEntity: PostMeta::class, indexBy: 'metaKey')]
    #[Context(normalizationContext: ['groups' => 'read_meta'])]
    #[Groups(['read_post_details', 'read_post_assoc', 'read_post_meta'])]
    protected Collection $meta;

    /**
     * @var Collection<Comment>
     */
    #[ORM\OneToMany(mappedBy: 'post', targetEntity: Comment::class)]
    #[Groups(['read_post_details', 'read_post_assoc', 'read_post_comments'])]
    protected Collection $comments;

    public function __construct()
    {
        $this->children = new ArrayCollection();
        $this->termRelationships = new ArrayCollection();
        $this->meta = new ArrayCollection();
        $this->comments = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function setId(?int $id): Post
    {
        $this->id = $id;
        return $this;
    }

    public function getAuthor(): User
    {
        return $this->author;
    }

    public function setAuthor(User $author): Post
    {
        $this->author = $author;
        return $this;
    }

    public function getDate(): DateTimeInterface
    {
        return $this->date ?? new \DateTime();
    }

    public function setDate(DateTimeInterface $date): Post
    {
        $this->date = $date;
        return $this;
    }

    public function getDateGmt(): DateTimeInterface
    {
        return $this->dateGmt;
    }

    public function setDateGmt(DateTimeInterface $dateGmt): Post
    {
        $this->dateGmt = $dateGmt;
        return $this;
    }

    public function getContent(): ?string
    {
        return $this->content;
    }

    public function setContent(?string $content): Post
    {
        $this->content = $content;
        return $this;
    }

    public function getTitle(): ?string
    {
        return $this->title;
    }

    public function setTitle(?string $title): Post
    {
        $this->title = $title;
        return $this;
    }

    public function getExcerpt(): ?string
    {
        return $this->excerpt;
    }

    public function setExcerpt(?string $excerpt): Post
    {
        $this->excerpt = $excerpt;
        return $this;
    }

    public function getStatus(): string
    {
        return $this->status;
    }

    public function setStatus(string $status): Post
    {
        $this->status = $status;
        return $this;
    }

    public function getCommentStatus(): string
    {
        return $this->commentStatus;
    }

    public function setCommentStatus(string $commentStatus): Post
    {
        $this->commentStatus = $commentStatus;
        return $this;
    }

    public function getPingStatus(): string
    {
        return $this->pingStatus;
    }

    public function setPingStatus(string $pingStatus): Post
    {
        $this->pingStatus = $pingStatus;
        return $this;
    }

    public function getPassword(): string
    {
        return $this->password;
    }

    public function setPassword(string $password): Post
    {
        $this->password = $password;
        return $this;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): Post
    {
        $this->name = $name;
        return $this;
    }

    public function getToPing(): ?string
    {
        return $this->toPing;
    }

    public function setToPing(?string $toPing): Post
    {
        $this->toPing = $toPing;
        return $this;
    }

    public function getPinged(): ?string
    {
        return $this->pinged;
    }

    public function setPinged(?string $pinged): Post
    {
        $this->pinged = $pinged;
        return $this;
    }

    public function getUpdatedAt(): DateTimeInterface
    {
        return $this->updatedAt;
    }

    public function setUpdatedAt(DateTimeInterface $updatedAt): Post
    {
        $this->updatedAt = $updatedAt;
        return $this;
    }

    public function getUpdatedAtGmt(): DateTimeInterface
    {
        return $this->updatedAtGmt;
    }

    public function setUpdatedAtGmt(DateTimeInterface $updatedAtGmt): Post
    {
        $this->updatedAtGmt = $updatedAtGmt;
        return $this;
    }

    public function getContentFiltered(): ?string
    {
        return $this->contentFiltered;
    }

    public function setContentFiltered(?string $contentFiltered): Post
    {
        $this->contentFiltered = $contentFiltered;
        return $this;
    }

    public function getParent(): ?Post
    {
        return $this->parent;
    }

    public function setParent(?Post $parent): Post
    {
        $this->parent = $parent;
        return $this;
    }

    public function getChildren(): Collection
    {
        return $this->children;
    }

    public function setChildren(Collection $children): Post
    {
        $this->children = $children;
        return $this;
    }

    public function getGuid(): string
    {
        return $this->guid;
    }

    public function setGuid(string $guid): Post
    {
        $this->guid = $guid;
        return $this;
    }

    public function getMenuOrder(): int
    {
        return $this->menuOrder;
    }

    public function setMenuOrder(int $menuOrder): Post
    {
        $this->menuOrder = $menuOrder;
        return $this;
    }

    public function getMimeType(): string
    {
        return $this->mimeType;
    }

    public function setMimeType(string $mimeType): Post
    {
        $this->mimeType = $mimeType;
        return $this;
    }

    public function getCommentCount(): int
    {
        return $this->commentCount;
    }

    public function setCommentCount(int $commentCount): Post
    {
        $this->commentCount = $commentCount;
        return $this;
    }

    public function getTermRelationships(): Collection
    {
        return $this->termRelationships;
    }

    public function setTermRelationships(Collection $termRelationships): Post
    {
        $this->termRelationships = $termRelationships;
        return $this;
    }

    public function getMeta(): Collection
    {
        return $this->meta;
    }

    public function setMeta(Collection $meta): Post
    {
        $this->meta = $meta;
        return $this;
    }

    public function getComments(): Collection
    {
        return $this->comments;
    }

    public function setComments(Collection $comments): Post
    {
        $this->comments = $comments;
        return $this;
    }

}
