<?php

namespace App\Blog\Entity;

use App\Auth\Entity\User;
use App\Location\Entity\City;
use App\Representation\Entity\Representation;
use Doctrine\ORM\Mapping as ORM;
use App\Blog\Repository\BlogRepository;
use Symfony\Component\Uid\Uuid;

#[ORM\Entity(repositoryClass: BlogRepository::class)]
#[ORM\Table(name: 'blogs')]
#[ORM\Index(columns: ['status', 'created_at'], name: 'idx_blogs_status')]
#[ORM\Index(columns: ['city_id'], name: 'idx_blogs_city')]
#[ORM\Index(columns: ['review_status', 'created_at'], name: 'idx_blogs_review_status')]
#[ORM\Index(columns: ['scheduled_at'], name: 'idx_blogs_scheduled_at')]
#[ORM\Index(columns: ['representation_id', 'created_at'], name: 'idx_blogs_representation')]
class Blog
{
    public const STATUS_DRAFT     = 'draft';
    public const STATUS_PUBLISHED = 'published';
    public const STATUS_ARCHIVED  = 'archived';

    // Medical-review gate. NULL is the permanent meaning "not part of the review
    // workflow" — a post created manually by an admin, which never needs a doctor's
    // approval. The content pipeline sets REVIEW_PENDING on every generated draft;
    // only REVIEW_APPROVED may be published by the pipeline.
    public const REVIEW_PENDING  = 'pending_review';
    public const REVIEW_APPROVED = 'approved';
    public const REVIEW_REJECTED = 'rejected';

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

    #[ORM\Column(type: 'string', length: 36, unique: true)]
    private string $uuid;

    #[ORM\Column(type: 'string', length: 255)]
    private string $title;

    #[ORM\Column(type: 'string', length: 255, unique: true)]
    private string $slug;

    #[ORM\Column(type: 'text')]
    private string $body;

    #[ORM\Column(type: 'string', length: 500, nullable: true)]
    private ?string $summary = null;

    #[ORM\Column(type: 'string', length: 500, nullable: true)]
    private ?string $imageUrl = null;

    #[ORM\Column(name: 'image_path', type: 'string', length: 500, nullable: true)]
    private ?string $imagePath = null;

    #[ORM\ManyToOne(targetEntity: User::class)]
    #[ORM\JoinColumn(name: 'author_id', referencedColumnName: 'id', nullable: false, onDelete: 'RESTRICT')]
    private User $author;

    // شهر پست. NULL معنای دائمی دارد: «پست سراسری» که روی دامنهٔ اصلی canonical
    // می‌شود. سایت عمومی چند-دامنه‌ای بر پایهٔ همین تفکیک تصمیم می‌گیرد پست را روی
    // دامنهٔ شهر نشان دهد یا روی دامنهٔ اصلی.
    #[ORM\ManyToOne(targetEntity: City::class)]
    #[ORM\JoinColumn(name: 'city_id', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')]
    private ?City $city = null;

    #[ORM\Column(type: 'json')]
    private array $tags = [];

    // Independent sources this article's facts were drawn from — the E-E-A-T
    // signal shown on the published post. Each item: { url, title }.
    #[ORM\Column(type: 'json')]
    private array $sources = [];

    #[ORM\Column(type: 'string', length: 20)]
    private string $status = self::STATUS_DRAFT;

    // NULL = manual admin post, outside the review workflow. Set by the pipeline.
    #[ORM\Column(name: 'review_status', type: 'string', length: 20, nullable: true)]
    private ?string $reviewStatus = null;

    // The doctor who reviewed. Kept even if their user is later removed.
    #[ORM\ManyToOne(targetEntity: User::class)]
    #[ORM\JoinColumn(name: 'reviewer_id', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')]
    private ?User $reviewer = null;

    #[ORM\Column(name: 'reviewed_at', type: 'integer', nullable: true)]
    private ?int $reviewedAt = null;

    #[ORM\Column(name: 'review_note', type: 'string', length: 500, nullable: true)]
    private ?string $reviewNote = null;

    // Stable identity of the pipeline topic (specialty + angle). Unique so a
    // re-run is idempotent and never creates a duplicate post. NULL for manual posts.
    #[ORM\Column(name: 'topic_slug', type: 'string', length: 255, nullable: true, unique: true)]
    private ?string $topicSlug = null;

    // ── SEO fields (all nullable; a plain post may leave them empty) ──────────
    #[ORM\Column(name: 'meta_title', type: 'string', length: 255, nullable: true)]
    private ?string $metaTitle = null;

    #[ORM\Column(name: 'meta_description', type: 'string', length: 500, nullable: true)]
    private ?string $metaDescription = null;

    #[ORM\Column(name: 'primary_keyword', type: 'string', length: 255, nullable: true)]
    private ?string $primaryKeyword = null;

    #[ORM\Column(name: 'secondary_keywords', type: 'json')]
    private array $secondaryKeywords = [];

    /** [{ "q": "...", "a": "..." }] — rendered as FAQPage JSON-LD on the site. */
    #[ORM\Column(type: 'json')]
    private array $faq = [];

    /** [{ "url": "...", "anchor": "..." }] internal link suggestions. */
    #[ORM\Column(name: 'internal_links', type: 'json')]
    private array $internalLinks = [];

    #[ORM\Column(name: 'external_links', type: 'json')]
    private array $externalLinks = [];

    #[ORM\Column(name: 'reading_time', type: 'integer', nullable: true)]
    private ?int $readingTime = null;

    #[ORM\Column(name: 'canonical_url', type: 'string', length: 500, nullable: true)]
    private ?string $canonicalUrl = null;

    #[ORM\Column(name: 'og_image', type: 'string', length: 500, nullable: true)]
    private ?string $ogImage = null;

    // ── Scheduling ───────────────────────────────────────────────────────────
    // Unix timestamp for automatic publish. NULL = publish manually. A scheduled
    // AI post publishes only once review_status = approved (the review gate wins).
    #[ORM\Column(name: 'scheduled_at', type: 'integer', nullable: true)]
    private ?int $scheduledAt = null;

    // ── Representative ownership ──────────────────────────────────────────────
    // NULL = an admin/nationwide post. Set when a representative authors a post
    // for their own domain; city must be one of the representative's coverage cities.
    #[ORM\ManyToOne(targetEntity: Representation::class)]
    #[ORM\JoinColumn(name: 'representation_id', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')]
    private ?Representation $representation = null;

    #[ORM\Column(name: 'created_at', type: 'integer')]
    private int $createdAt;

    #[ORM\Column(name: 'updated_at', type: 'integer')]
    private int $updatedAt;

    public function __construct(User $author, string $title, string $body)
    {
        $this->uuid      = Uuid::v4()->toRfc4122();
        $this->author    = $author;
        $this->title     = $title;
        $this->slug      = $this->generateSlug($title);
        $this->body      = $body;
        $this->createdAt = time();
        $this->updatedAt = time();
    }

    public function getId(): ?int       { return $this->id; }
    public function getUuid(): string   { return $this->uuid; }
    public function getTitle(): string  { return $this->title; }
    public function getSlug(): string   { return $this->slug; }
    public function getBody(): string   { return $this->body; }
    public function getSummary(): ?string { return $this->summary; }
    public function getImageUrl(): ?string { return $this->imageUrl; }
    public function getImagePath(): ?string { return $this->imagePath; }
    public function getAuthor(): User   { return $this->author; }
    public function getTags(): array    { return $this->tags; }
    public function getSources(): array { return $this->sources; }
    public function getStatus(): string { return $this->status; }
    public function getReviewStatus(): ?string { return $this->reviewStatus; }
    public function getReviewer(): ?User { return $this->reviewer; }
    public function getReviewedAt(): ?int { return $this->reviewedAt; }
    public function getReviewNote(): ?string { return $this->reviewNote; }
    public function getTopicSlug(): ?string { return $this->topicSlug; }
    public function getMetaTitle(): ?string { return $this->metaTitle; }
    public function getMetaDescription(): ?string { return $this->metaDescription; }
    public function getPrimaryKeyword(): ?string { return $this->primaryKeyword; }
    public function getSecondaryKeywords(): array { return $this->secondaryKeywords; }
    public function getFaq(): array { return $this->faq; }
    public function getInternalLinks(): array { return $this->internalLinks; }
    public function getExternalLinks(): array { return $this->externalLinks; }
    public function getReadingTime(): ?int { return $this->readingTime; }
    public function getCanonicalUrl(): ?string { return $this->canonicalUrl; }
    public function getOgImage(): ?string { return $this->ogImage; }
    public function getScheduledAt(): ?int { return $this->scheduledAt; }
    public function getRepresentation(): ?Representation { return $this->representation; }
    public function getCity(): ?City    { return $this->city; }

    public function setTitle(string $v): self    { $this->title = $v; $this->touch(); return $this; }
    public function setSlug(string $v): self     { $this->slug = $v; $this->touch(); return $this; }
    public function setBody(string $v): self     { $this->body = $v; $this->touch(); return $this; }
    public function setSummary(?string $v): self { $this->summary = $v; $this->touch(); return $this; }
    public function setImageUrl(?string $v): self  { $this->imageUrl = $v; $this->touch(); return $this; }
    public function setImagePath(?string $v): self { $this->imagePath = $v; $this->touch(); return $this; }
    public function setTags(array $v): self      { $this->tags = $v; $this->touch(); return $this; }
    public function setSources(array $v): self   { $this->sources = $v; $this->touch(); return $this; }
    public function setStatus(string $v): self   { $this->status = $v; $this->touch(); return $this; }
    public function setReviewStatus(?string $v): self { $this->reviewStatus = $v; $this->touch(); return $this; }
    public function setReviewer(?User $v): self   { $this->reviewer = $v; $this->touch(); return $this; }
    public function setReviewedAt(?int $v): self  { $this->reviewedAt = $v; $this->touch(); return $this; }
    public function setReviewNote(?string $v): self { $this->reviewNote = $v; $this->touch(); return $this; }
    public function setTopicSlug(?string $v): self { $this->topicSlug = $v; $this->touch(); return $this; }
    public function setMetaTitle(?string $v): self { $this->metaTitle = $v; $this->touch(); return $this; }
    public function setMetaDescription(?string $v): self { $this->metaDescription = $v; $this->touch(); return $this; }
    public function setPrimaryKeyword(?string $v): self { $this->primaryKeyword = $v; $this->touch(); return $this; }
    public function setSecondaryKeywords(array $v): self { $this->secondaryKeywords = array_values($v); $this->touch(); return $this; }
    public function setFaq(array $v): self { $this->faq = array_values($v); $this->touch(); return $this; }
    public function setInternalLinks(array $v): self { $this->internalLinks = array_values($v); $this->touch(); return $this; }
    public function setExternalLinks(array $v): self { $this->externalLinks = array_values($v); $this->touch(); return $this; }
    public function setReadingTime(?int $v): self { $this->readingTime = $v; $this->touch(); return $this; }
    public function setCanonicalUrl(?string $v): self { $this->canonicalUrl = $v; $this->touch(); return $this; }
    public function setOgImage(?string $v): self { $this->ogImage = $v; $this->touch(); return $this; }
    public function setScheduledAt(?int $v): self { $this->scheduledAt = $v; $this->touch(); return $this; }
    public function setRepresentation(?Representation $v): self { $this->representation = $v; $this->touch(); return $this; }
    /** null = پست سراسری (روی همهٔ دامنه‌ها، canonical روی دامنهٔ اصلی) */
    public function setCity(?City $v): self      { $this->city = $v; $this->touch(); return $this; }

    /** Record a doctor's review decision in one call. */
    public function applyReview(string $decision, User $reviewer, ?string $note = null): self
    {
        $this->reviewStatus = $decision;
        $this->reviewer     = $reviewer;
        $this->reviewedAt   = time();
        $this->reviewNote   = $note;
        $this->touch();
        return $this;
    }

    private function touch(): void { $this->updatedAt = time(); }

    private function generateSlug(string $title): string
    {
        $slug = mb_strtolower(trim($title));
        $slug = preg_replace('/\s+/', '-', $slug);
        $slug = preg_replace('/[^a-z0-9\-\p{Arabic}]/u', '', $slug);
        return $slug . '-' . substr(str_replace('-', '', $this->uuid), 0, 8);
    }

    public function toArray(): array
    {
        return [
            'uuid'       => $this->uuid,
            'title'      => $this->title,
            'slug'       => $this->slug,
            'summary'    => $this->summary,
            'body'       => $this->body,
            'image_url'  => $this->imageUrl,
            'tags'       => $this->tags,
            'sources'    => $this->sources,
            'status'     => $this->status,
            'review_status' => $this->reviewStatus,
            'reviewer'   => $this->reviewerToArray(),
            'reviewed_at'=> $this->reviewedAt,
            'review_note'=> $this->reviewNote,
            'topic_slug' => $this->topicSlug,
            'meta_title' => $this->metaTitle,
            'meta_description' => $this->metaDescription,
            'primary_keyword' => $this->primaryKeyword,
            'secondary_keywords' => $this->secondaryKeywords,
            'faq'        => $this->faq,
            'internal_links' => $this->internalLinks,
            'external_links' => $this->externalLinks,
            'reading_time' => $this->readingTime,
            'canonical_url' => $this->canonicalUrl,
            'og_image'   => $this->ogImage,
            'scheduled_at' => $this->scheduledAt,
            'representation' => $this->representationToArray(),
            'author'     => $this->authorToArray(),
            'city'       => $this->cityToArray(),
            'created_at' => $this->createdAt,
            'updated_at' => $this->updatedAt,
        ];
    }

    /** The owning representative, or null for admin/nationwide posts. */
    private function representationToArray(): ?array
    {
        if ($this->representation === null) {
            return null;
        }
        try {
            return [
                'uuid'   => $this->representation->getUuid(),
                'name'   => $this->representation->getFullName(),
                'domain' => $this->representation->getDomain(),
            ];
        } catch (\Doctrine\ORM\EntityNotFoundException) {
            return null;
        }
    }

    /** The reviewing doctor, or null. Same defensive lazy-proxy handling as author. */
    private function reviewerToArray(): ?array
    {
        if ($this->reviewer === null) {
            return null;
        }
        try {
            return [
                'uuid' => $this->reviewer->getUuid(),
                'name' => $this->reviewer->getRealName(),
            ];
        } catch (\Doctrine\ORM\EntityNotFoundException) {
            return null;
        }
    }

    /** null = پست سراسری. مصرف‌کننده روی همین null تصمیم canonical می‌گیرد. */
    private function cityToArray(): ?array
    {
        if ($this->city === null) {
            return null;
        }

        return [
            'id'   => (string) $this->city->getId(),
            'name' => $this->city->getName(),
        ];
    }

    private function authorToArray(): ?array
    {
        if ($this->author === null) {
            return null;
        }
        // The referenced user may have been deleted; a lazy proxy then throws
        // EntityNotFoundException on access. Treat a missing author as null.
        try {
            return [
                'uuid' => $this->author->getUuid(),
                'name' => $this->author->getRealName(),
            ];
        } catch (\Doctrine\ORM\EntityNotFoundException) {
            return null;
        }
    }

    public function toListArray(): array
    {
        return [
            'uuid'       => $this->uuid,
            'title'      => $this->title,
            'slug'       => $this->slug,
            'summary'    => $this->summary,
            'image_url'  => $this->imageUrl,
            'tags'       => $this->tags,
            'status'     => $this->status,
            'review_status' => $this->reviewStatus,
            'reviewer'   => $this->reviewerToArray(),
            'topic_slug' => $this->topicSlug,
            'scheduled_at' => $this->scheduledAt,
            'representation' => $this->representationToArray(),
            'city'       => $this->cityToArray(),
            'created_at' => $this->createdAt,
        ];
    }
}
