<?php

namespace Modules\Feedback\Entities;

use App\Traits\QueryCacheable;
use Deligoez\LaravelModelHashId\Traits\HasHashId;
use Deligoez\LaravelModelHashId\Traits\HasHashIdRouting;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Modules\Event\Entities\Event;
use Modules\Feedback\Database\Factories\FeedbackFactory;
use Yajra\DataTables\Facades\DataTables;

class Feedback extends Model
{
    const STATUS_PENDING = 'pending';
    const STATUS_APPROVED = 'approved';
    const STATUS_DISABLED = 'disabled';

    use HasFactory;
    use HasHashId;
    use HasHashIdRouting;
    use SoftDeletes;
    use QueryCacheable;

    protected $table = 'feedbacks';

    /**
     * Specify the amount of time to cache queries.
     * Do not specify or set it to null to disable caching.
     *
     * @var int|\DateTime
     */
    public $cacheFor = 3600;

    /**
     * The tags for the query cache. Can be useful
     * if flushing cache for specific tags only.
     *
     * @var null|array
     */
    public $cacheTags = ['feedbacks'];

    /**
     * Invalidate the cache automatically
     * upon update in the database.
     *
     * @var bool
     */
    protected static $flushCacheOnUpdate = true;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'event_id',
        'name',
        'organization',
        'session',
        'message',
        'status',
        'is_anonymous',
        'deleted_by',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        // 'deleted_at',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'is_anonymous' => 'boolean',
        'updated_at' => 'datetime:Y-m-d H:i:s',
        'created_at' => 'datetime:Y-m-d H:i:s',
        'deleted_at' => 'datetime:Y-m-d H:i:s',
    ];

    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = [
        //
    ];

    /**
     * Create a new factory instance for the model.
     */
    protected static function newFactory()
    {
        return FeedbackFactory::new();
    }

    public function event()
    {
        return $this->belongsTo(Event::class);
    }

    public function scopeAnonymous($query)
    {
        $query->where('feedbacks.is_anonymous', true);
    }

    public function scopePending($query)
    {
        $query->where('feedbacks.status', self::STATUS_PENDING);
    }

    public function scopeApproved($query)
    {
        $query->where('feedbacks.status', self::STATUS_APPROVED);
    }

    public function scopeDisabled($query)
    {
        $query->where('feedbacks.status', self::STATUS_DISABLED);
    }

    public function scopeFilters($query, Request $request)
    {
        $query->when($request->has('event'), function ($query) use ($request) {
            return $query->where('event_id', $request->event);
        });

        $query->when($request->has('anonymous'), function ($query) use ($request) {
            return $query->where('is_anonymous', $request->anonymous == 'yes');
        });

        $query->when($request->has('status'), function ($query) use ($request) {
            return $query->where('status', $request->status);
        });

        $query->when($request->has('range'), function ($query) use ($request) {
            $date_range = explode(' to ', $request->range);

            if (count($date_range) == 2) {
                $from = new Carbon($date_range[0]);
                $to = new Carbon($date_range[1]);

                $query->whereBetween('created_at', [$from->startOfDay(), $to->endOfDay()]);
            } else if (count($date_range) == 1) {
                $query->whereDate('created_at', $date_range[0]);
            }

            return $query;
        });
    }

    public static function makeDataTable($source, $trash = false)
    {
        return DataTables::of($source)
            ->addColumn('event', function (self $row) {
                return view('admin.datatables.related', [
                    'row' => $row,
                    'relation' => 'event',
                    'route' => 'event.edit',
                    'label' => 'title'
                ]);
            })
            ->editColumn('status', function (self $row) {
                return view('admin.datatables.status', [
                    'active' => $row->status == self::STATUS_APPROVED,
                    'empty' => $row->status == self::STATUS_PENDING,
                    'true' => self::STATUS_APPROVED,
                    'false' => self::STATUS_DISABLED,
                    'unknown' => self::STATUS_PENDING,
                ]);
            })
            ->addColumn('anonymous', function (self $row) {
                return view('admin.datatables.status', ['active' => $row->is_anonymous, 'true' => __('Yes'), 'false' => __('No')]);
            })
            ->editColumn('message', function (self $row) {
                return view('admin.datatables.limit', ['title' => $row->message, 'limit' => 50]);
            })
            ->addColumn('actions', function (self $row) use ($trash) {
                $actions = ['row' => $row];

                if ($trash) {
                    $actions['restore_route'] = 'feedback.restore';
                } else {
                    $actions['update_route'] = 'feedback.edit';
                    $actions['delete_route'] = 'feedback.destroy';
                }

                return view('admin.datatables.actions', $actions);
            })
            // to fixed yajra weird timezone return
            ->editColumn('created_at', fn($row) => $row->created_at)
            ->editColumn('updated_at', fn($row) => $row->updated_at)
            ->editColumn('deleted_at', fn($row) => $row->deleted_at)
            ->make(true);
    }

    public static function listStatuses()
    {
        return [
            self::STATUS_PENDING,
            self::STATUS_APPROVED,
            self::STATUS_DISABLED,
        ];
    }
}
