<?php

namespace App\Models;

use App\Enums\PostType;
use App\Enums\GroupType;
use App\Enums\DeletedType;
use App\Enums\PostAvailableType;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Post extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'content',
        'user_id',
        'type',
        'origin_id',
        'is_seen',
        'is_accepted',
        'deleted_type',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'type' => PostType::class,
        'is_seen' => 'boolean',
        'is_accepted' => 'boolean',
        'deleted_type' => DeletedType::class,
    ];

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

    public function group(): BelongsTo
    {
        return $this->belongsTo(Group::class, 'origin_id')->whereExists(function ($query) {
            $query->from('posts')->whereColumn('groups.id', 'posts.origin_id')->where('posts.type', PostType::GROUP);
        });
    }

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

    public function likes(): BelongsToMany
    {
        return $this->belongsToMany(User::class, 'post_likes')->withPivot('created_at');
    }

    public function images(): MorphMany
    {
        return $this->morphMany(Image::class, 'imageable');
    }

    public function scopeType($query, PostType $type)
    {
        $query->where('type', $type);
    }

    public function scopeSeen($query, $value)
    {
        $query->where('is_seen', $value);
    }

    public function scopeAccepted($query, $value)
    {
        $query->where('is_accepted', $value);
    }

    public function scopeOwned($query)
    {
        $query->where('user_id', auth()->id());
    }

    public function scopeFilter($query, $filters)
    {
        $query->when($filters['search'] ?? false, function ($query, $searchText) {
            $query->whereHas('user', function ($query) use ($searchText) {
                $query->whereHas('profile', function ($query) use ($searchText) {
                    $query->where(function ($query) use ($searchText) {
                        $query->where('first_name', 'like', '%' . $searchText . '%')
                            ->orWhere('last_name', 'like', '%' . $searchText . '%');
                    });
                });
            })->orWhere('content', 'like', '%' . $searchText . '%');
        });
    }

    public function scopeAvailable($query, PostAvailableType $type)
    {
        $loginUser = auth()->user();
        switch ($type) {
            case PostAvailableType::LIST:
                if ($loginUser) {
                    $query->accepted(true)
                        ->where(function ($query) use ($loginUser) {
                            $query->whereIn('type', [PostType::PUBLIC, PostType::SHARE_PUBLIC])
                                ->orWhere(function ($query) use ($loginUser) {
                                    $friends = $loginUser->getFriends()->pluck('id')->toArray();
                                    $query->whereIn('type', [PostType::FRIENDS, PostType::SHARE_FRIENDS])
                                        ->whereIn('user_id', [$loginUser->id, ...$friends]);
                                })
                                ->orWhere(function ($query) use ($loginUser) {
                                    $query->whereIn('type', [PostType::PRIVATE, PostType::SHARE_PRIVATE, PostType::GROUP])
                                        ->where('user_id', $loginUser->id);
                                })
                                ->orWhere(function ($query) use ($loginUser) {
                                    $groups = $loginUser->groups()->pluck('groups.id')->toArray();
                                    $query->where('type', PostType::GROUP)
                                        ->whereIn('origin_id', $groups);
                                });
                        });
                } else {
                    $query->accepted(true)
                        ->where(function ($query) {
                            $query->whereIn('type', [PostType::PUBLIC, PostType::SHARE_PUBLIC])
                                ->orWhere(function ($query) {
                                    $query->where('type', PostType::GROUP)
                                        ->whereHas('group', function ($query) {
                                            $query->where('type', GroupType::PUBLIC);
                                        });
                                });
                        });
                }

                break;
            case PostAvailableType::GROUP:
                $query->where('type', PostType::GROUP)
                    ->accepted(true)
                    ->where(function ($query) use ($loginUser) {
                        $query->whereHas('group', function ($query) {
                            $query->where('type', GroupType::PUBLIC);
                        });
                        if ($loginUser) {
                            $groups = $loginUser->groups()->pluck('groups.id')->toArray();
                            $query->orWhereIn('origin_id', $groups);
                        }
                    });
                break;
            case PostAvailableType::SHOW:
                if ($loginUser) {
                    if (!$loginUser->isAdmin()) {
                        $query->where(function ($query) use ($loginUser) {
                            $query->whereIn('type', [PostType::PUBLIC, PostType::SHARE_PUBLIC])
                                ->orWhere(function ($query) use ($loginUser) {
                                    $friends = $loginUser->getFriends()->pluck('id')->toArray();
                                    $query->whereIn('type', [PostType::FRIENDS, PostType::SHARE_FRIENDS])
                                        ->whereIn('user_id', [$loginUser->id, ...$friends]);
                                })
                                ->orWhere(function ($query) use ($loginUser) {
                                    $query->whereIn('type', [PostType::PRIVATE, PostType::SHARE_PRIVATE, PostType::GROUP])
                                        ->where('user_id', $loginUser->id);
                                })
                                ->orWhere(function ($query) use ($loginUser) {
                                    $query->where('type', PostType::GROUP)
                                        ->where(function ($query) use ($loginUser) {
                                            $query->where(function ($query) {
                                                $query->accepted(true)
                                                    ->whereHas('group', function ($query) {
                                                        $query->where('type', GroupType::PUBLIC);
                                                    });
                                            })
                                                ->orWhere(function ($query) use ($loginUser) {
                                                    $groups = $loginUser->groups()->pluck('groups.id')->toArray();
                                                    $query->whereIn('origin_id', $groups)
                                                        ->where(function ($query) use ($loginUser) {
                                                            $query->where(function ($query) use ($loginUser) {
                                                                $query->accepted(false)
                                                                    ->where(function ($query) use ($loginUser) {
                                                                        $query->whereHas('group', function ($query) use ($loginUser) {
                                                                            $query->where('user_id', $loginUser->id);
                                                                        })
                                                                            ->orWhere('user_id', $loginUser->id);
                                                                    });
                                                            })
                                                                ->orWhere('is_accepted', true);
                                                        });
                                                });
                                        });
                                });
                        });
                    }
                } else {
                    $query->accepted(true)
                        ->where(function ($query) {
                            $query->whereIn('type', [PostType::PUBLIC, PostType::SHARE_PUBLIC])
                                ->orWhere(function ($query) {
                                    $query->where('type', PostType::GROUP)
                                        ->whereHas('group', function ($query) {
                                            $query->where('type', GroupType::PUBLIC);
                                        });
                                });
                        });
                }

                break;
        }
    }
}
