<?php

namespace Modules\Speaker\Entities;

use App\Supports\Address;
use App\Traits\QueryCacheable;
use Deligoez\LaravelModelHashId\Traits\HasHashId;
use Deligoez\LaravelModelHashId\Traits\HasHashIdRouting;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Http\Request;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Carbon;
use Modules\Admin\Entities\Admin;
use Modules\Country\Entities\Country;
use Modules\Event\Entities\Event;
use Modules\Event\Entities\EventSchedule;
use Modules\Speaker\Database\Factories\SpeakerFactory;
use Yajra\DataTables\Facades\DataTables;

class Speaker extends Model
{
    use Notifiable;
    use HasFactory;
    use HasHashId;
    use HasHashIdRouting;
    use SoftDeletes;
    use QueryCacheable;

    /**
     * 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 = ['speakers'];

    /**
     * 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 = [
        'name',
        'designation',
        'picture',
        'gender',
        'email',
        'contact_no',
        'description',
        'password',
        // 'remember_token',
        'address_line_1',
        'address_line_2',
        'postcode',
        'country_id',
        'country_iso',
        'country_name',
        'is_active',
        // 'last_login_at',
        // 'email_verified_at',
        'created_by',
        'deleted_by',
    ];

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

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'is_active' => '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',
        'email_verified_at' => 'datetime:Y-m-d H:i:s',
        'last_login_at' => 'datetime:Y-m-d H:i:s',
    ];

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

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

    public function country()
    {
        return $this->belongsTo(Country::class);
    }

    public function creator()
    {
        return $this->belongsTo(Admin::class, 'created_by');
    }

    public function deletor()
    {
        return $this->belongsTo(Admin::class, 'deleted_by');
    }

    public function events()
    {
        return $this->belongsToMany(Event::class);
    }

    public function schedules()
    {
        return $this->belongsToMany(EventSchedule::class, 'schedule_speaker')
            ->orderBy('date')->orderBy('position');
    }

    /**
     * Get the path to the profile picture
     *
     * @return string
     */
    public function getAvatarPathAttribute()
    {
        $default = uno()->avatar;

        if ($this->picture) {
            if (filter_var($this->picture, FILTER_VALIDATE_URL)) {
                return $this->picture;
            } else if (asset_exists($this->picture)) {
                return disk_public()->url($this->picture);
            } else {
                return $default;
            }
        }

        return $default;
    }

    protected function address(): Attribute
    {
        return Attribute::make(
            get: fn (mixed $value, array $attributes) => new Address(
                $attributes['address_line_1'] ?: 'N/A',
                $attributes['address_line_2'],
                $attributes['postcode'],
                $attributes['country_name'],
                $attributes['country_id'],
            ),
        );
    }

    public function scopeActive($query)
    {
        $query->where('speakers.is_active', true);
    }

    public function scopeFilters($query, Request $request, $fav = false)
    {
        $query->when($request->has('event'), function ($query) use ($request) {
            return $query->whereRelation('events', 'id', $request->event);
        });

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

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

        $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, $pricelist = false)
    {
        return DataTables::of($source)
            ->addIndexColumn()
            ->editColumn('description', function (self $row) {
                return view('admin.datatables.limit', ['title' => $row->description, 'limit' => 40]);
            })
            ->addColumn('avatar', function (self $row) {
                return view('admin.datatables.thumbnail', ['path' => $row->avatar_path]);
            })
            ->addColumn('country', function (self $row) {
                return true ? null : view('admin.datatables.related', [
                    'row' => $row,
                    'relation' => 'country',
                    // 'route' => 'country.edit',
                    'label' => 'name',
                    'allowed' => false,
                ]);
            })
            ->addColumn('status', function (self $row) {
                return view('admin.datatables.status', ['active' => $row->is_active]);
            })
            ->addColumn('actions', function (self $row) use ($trash) {
                $actions = ['row' => $row];

                if ($trash) {
                    $actions['restore_route'] = 'speaker.restore';
                } else {
                    $actions['update_route'] = 'speaker.edit';
                    $actions['delete_route'] = 'speaker.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);
    }
}
