<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Laravel\Scout\Searchable;

/**
 * @property int    $id
 * @property int    $user_id
 * @property string $type        text | artwork_share | upload | achievement
 * @property string $visibility  public | followers | private
 * @property string|null $body
 * @property array|null  $meta
 * @property int    $reactions_count
 * @property int    $comments_count
 * @property string $status      draft | scheduled | published
 * @property bool   $is_pinned
 * @property int|null $pinned_order
 * @property \Carbon\Carbon|null $publish_at
 * @property int    $impressions_count
 * @property float  $engagement_score
 * @property int    $saves_count
 */
class Post extends Model
{
    use HasFactory, SoftDeletes, Searchable;

    protected $table = 'posts';

    protected $fillable = [
        'user_id', 'type', 'visibility', 'body', 'meta',
        'reactions_count', 'comments_count',
        'is_pinned', 'pinned_order',
        'publish_at', 'status',
        'impressions_count', 'engagement_score', 'saves_count',
    ];

    protected $casts = [
        'meta'              => 'array',
        'reactions_count'   => 'integer',
        'comments_count'    => 'integer',
        'impressions_count' => 'integer',
        'saves_count'       => 'integer',
        'engagement_score'  => 'float',
        'is_pinned'         => 'boolean',
        'pinned_order'      => 'integer',
        'publish_at'        => 'datetime',
    ];

    // ─────────────────────────────────────────────────────────────────────────
    // Constants
    // ─────────────────────────────────────────────────────────────────────────

    public const TYPE_TEXT          = 'text';
    public const TYPE_ARTWORK_SHARE = 'artwork_share';
    public const TYPE_UPLOAD        = 'upload';
    public const TYPE_ACHIEVEMENT   = 'achievement';

    public const VISIBILITY_PUBLIC    = 'public';
    public const VISIBILITY_FOLLOWERS = 'followers';
    public const VISIBILITY_PRIVATE   = 'private';

    public const STATUS_DRAFT     = 'draft';
    public const STATUS_SCHEDULED = 'scheduled';
    public const STATUS_PUBLISHED = 'published';

    // ─────────────────────────────────────────────────────────────────────────
    // Relationships
    // ─────────────────────────────────────────────────────────────────────────

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function targets(): HasMany
    {
        return $this->hasMany(PostTarget::class);
    }

    /** Convenience: single artwork target for artwork_share posts */
    public function artworkTarget(): HasOne
    {
        return $this->hasOne(PostTarget::class)->where('target_type', 'artwork');
    }

    public function reactions(): HasMany
    {
        return $this->hasMany(PostReaction::class);
    }

    public function comments(): HasMany
    {
        return $this->hasMany(PostComment::class)->orderBy('created_at');
    }

    public function saves(): HasMany
    {
        return $this->hasMany(PostSave::class);
    }

    public function reports(): HasMany
    {
        return $this->hasMany(PostReport::class);
    }

    public function hashtags(): HasMany
    {
        return $this->hasMany(PostHashtag::class);
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Scopes
    // ─────────────────────────────────────────────────────────────────────────

    /** Posts visible to any public (non-authenticated) visitor */
    public function scopePublic($query)
    {
        return $query->where('visibility', self::VISIBILITY_PUBLIC);
    }

    /** Only published posts */
    public function scopePublished($query)
    {
        return $query->where('status', self::STATUS_PUBLISHED);
    }

    /** Only scheduled posts */
    public function scopeScheduled($query)
    {
        return $query->where('status', self::STATUS_SCHEDULED);
    }

    /** Posts visible to the given viewer (respects followers-only AND published status) */
    public function scopeVisibleTo($query, ?int $viewerId)
    {
        $query->where('status', self::STATUS_PUBLISHED);

        if (! $viewerId) {
            return $query->where('visibility', self::VISIBILITY_PUBLIC);
        }

        return $query->where(function ($q) use ($viewerId) {
            $q->where('visibility', self::VISIBILITY_PUBLIC)
              ->orWhere('user_id', $viewerId)
              ->orWhere(function ($q2) use ($viewerId) {
                  $q2->where('visibility', self::VISIBILITY_FOLLOWERS)
                     ->whereIn('user_id', function ($sub) use ($viewerId) {
                         $sub->select('user_id')
                             ->from('user_followers')
                             ->where('follower_id', $viewerId);
                     });
              });
        });
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Scout (Meilisearch)
    // ─────────────────────────────────────────────────────────────────────────

    public function toSearchableArray(): array
    {
        return [
            'id'         => $this->id,
            'body'       => strip_tags($this->body ?? ''),
            'hashtags'   => $this->hashtags->pluck('tag')->toArray(),
            'user_id'    => $this->user_id,
            'type'       => $this->type,
            'visibility' => $this->visibility,
            'created_at' => $this->created_at?->timestamp,
        ];
    }

    public function shouldBeSearchable(): bool
    {
        return $this->status === self::STATUS_PUBLISHED
            && $this->visibility === self::VISIBILITY_PUBLIC;
    }
}
