<?php
namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Modules\Company\Models\Company;
use Modules\Core\Models\SEO;
use Modules\Gig\Models\Gig;
use Modules\Job\Models\Job;
use Modules\Job\Models\JobCandidate;
use Modules\Media\Helpers\FileHelper;
use Modules\Order\Models\Order;
use Modules\User\Models\UserViews;
use Modules\User\Models\UserWishList;

class BaseModel extends Model
{
    protected $dateFormat    = 'Y-m-d H:i:s';
    protected $slugField     = '';
    protected $slugFromField = '';
    protected $cleanFields = [];
    protected $seo_type;
    public $translationForeignKey = 'origin_id';
    public $type = 'default';

    public static function getModelName()
    {

    }

    public static function getAsMenuItem($id)
    {
        return false;
    }

    public static function searchForMenu($q = false)
    {
        return [];
    }

    public function save(array $options = [])
    {
        if ($this->create_user) {
            $this->update_user = Auth::id();
        } else {
            $this->create_user = Auth::id();
        }
        if ($this->slugField && $this->slugFromField) {
            $slugField = $this->slugField;
            $slug = request()->get($slugField);
            if ($slug){
                $this->$slugField = $slug;
                $count = static::whereRaw("slug RLIKE '^{$slug}(-[0-9]+)?$'")->whereNotNull('slug')->where('id', '!=', $this->id)->count();
                $this->$slugField = $count ? "{$this->$slugField}-{$count}" : $this->$slugField;
            }else {
                $this->$slugField = $this->generateSlug($this->$slugField);
            }

        }
        $this->cleanFields();
        return parent::save($options); // TODO: Change the autogenerated stub
    }

    /**
     * @todo HTMLPurifier
     * @param array $fields
     */
    protected function cleanFields($fields = [])
    {
        if (empty($fields))
            $fields = $this->cleanFields;
        if (!empty($fields)) {
            foreach ($fields as $field) {

                if ($this->$field !== NULL) {
                    $this->$field = clean($this->$field,'youtube');
                }
            }
        }
    }

    public function generateSlug($string = false, $count = 0)
    {
        $slugFromField = $this->slugFromField;
        if (empty($string))
            $string = $this->$slugFromField;
        $slug = $newSlug = $this->strToSlug($string);
        $newSlug = $slug . ($count ? '-' . $count : '');
        $model = static::select('count(id)');
        if ($this->id) {
            $model->where('id', '<>', $this->id);
        }
        $check = $model->where($this->slugField, $newSlug)->count();
        if (!empty($check)) {
            return $this->generateSlug($slug, $count + 1);
        }
        return $newSlug;
    }

    // Add Support for non-ascii string
    // Example বাংলাদেশ   ব্যাংকের    রিজার্ভের  অর্থ  চুরির   ঘটনায়   ফিলিপাইনের
    protected function strToSlug($string) {
        $slug = Str::slug($string);
        if(empty($slug)){
            $slug = preg_replace('/\s+/u', '-', trim($string));
        }
        return $slug;
    }

    public function getDetailUrl()
    {
        return '';
    }

    public function getEditUrl()
    {
        return '';
    }

    public function getAuthor()
    {
        return $this->belongsTo("App\User", "create_user", "id")->withDefault();
    }

    public function author()
    {
        return $this->belongsTo("App\User", "create_user", "id")->withDefault();
    }

    public function vendor(){
        return $this->belongsTo("App\User", "vendor_id", 'id')->withDefault();
    }

    public function cacheKey(){
        return strtolower($this->table);
    }

    public function findById($id)
    {
        return Cache::rememberForever($this->cacheKey() . ':' . $id, function () use ($id) {
            return $this->find($id);
        });
    }

    public function currentUser()
    {
        return Auth::user();
    }

    public function origin(){
        return $this->hasOne(get_class($this),'id','origin_id');
    }

    public function getIsTranslationAttribute(){
        if($this->origin_id) return true;
        return false;
    }


    public function getTranslationsByLocalesAttribute(){
        $translations = $this->translations;
        $res = [];

        foreach ($translations as $translation)
        {
            $res[$translation->lang]  = $translation;
        }
        return $res;
    }

    public function getIsPublishedAttribute(){

        if($this->is_translation){

            $origin = $this->origin;

            if(empty($origin)) return false;
            return $origin->status == 'publish';
        }else{
            return $this->status == 'publish';
        }
    }

    public function saveSEO(\Illuminate\Http\Request $request , $locale = false)
    {
        if(!$this->seo_type) return;
        $seo_key = $this->seo_type;
        if(!empty($locale)) $seo_key = $seo_key."_".$locale;
        $meta = SEO::where('object_id', $this->id)->where('object_model', $seo_key)->first();
        if (!$meta) {
            $meta = new SEO();
            $meta->object_id = $this->id;
            $meta->object_model = $seo_key;
        }
        $meta->fill($request->input());
        return $meta->save();
    }

    public function getSeoMeta($locale = false)
    {
        if(!$this->seo_type) return;
        $seo_key = $this->seo_type;
        if(!empty($locale)) $seo_key = $seo_key."_".$locale;
        $meta = SEO::where('object_id',  $this->id ? $this->id : $this->origin_id )->where('object_model', $seo_key)->first();
        if(!empty($meta)){
            $meta = $meta->toArray();
        }
        $meta['slug'] = $this->slug;
        $meta['full_url'] = $this->getDetailUrl();
        $meta['service_title'] = $this->title ?? $this->name;
        $meta['service_desc'] = $this->short_desc;
        $meta['service_image'] = $this->image_id;
        return $meta;
    }

    public function getSeoMetaWithTranslation($locale,$translation){
        if(is_default_lang($locale)) return $this->getSeoMeta();
        if(!empty($translation->origin_id)){
            $meta = $translation->getSeoMeta( $locale );
            $meta['full_url'] = $this->getDetailUrl();
            $meta['slug'] = $this->slug;
            $meta['service_image'] = $this->image_id;;
            return $meta;
        }
    }
    /**
     * @internal will change to private
     */
    public function getTranslationModelNameDefault(): string
    {
        $modelName = get_class($this);

        return $modelName.config('translatable.translation_suffix', 'Translation');
    }

    public function translations(){
        return $this->hasMany($this->getTranslationModelNameDefault(),'origin_id');
    }
    public function translate($locale = false){
        $translations = $this->translations;
        if(!empty($translations)){
            foreach ($translations as $translation)
            {
                if($translation->locale == $locale) return $translation;
            }
        }
        return false;
    }
    public function getNewTranslation($locale){

        $modelName = $this->getTranslationModelNameDefault();

        $translation = new $modelName();
        $translation->locale = $locale;
        $translation->origin_id = $this->id;

        return $translation;
    }

    public function translateOrOrigin($locale = false){
        if(empty($locale) or is_default_lang($locale)){
            $a = $this->getNewTranslation($locale);
            $a->fill($this->getAttributes());
        }else{
            $a = $this->translate($locale);
            if(!empty($a)) return $a;
            $a = $this->getNewTranslation($locale);
            $a->fill($this->getAttributes());
        }
        if(!empty($this->casts))
        {
            foreach ($this->casts as $key=>$type){
                if(!empty($a->casts) and !empty($a->casts[$key])){
                    $a->setAttribute($key,$this->getAttribute($key));
                }
            }
        }
        return $a;
    }

    /**
     * @todo Save Translation or Origin Language
     * @param bool $locale
     * @param bool $saveSeo
     * @return bool|null
     */
    public function saveOriginOrTranslation($locale = false, $saveSeo = true)
    {
        if(!$locale or is_default_lang($locale) or empty(setting_item('site_enable_multi_lang'))){
            $res = $this->save();
            if($res && $saveSeo){
                $this->saveSEO(request());
            }
            return $res;

        }elseif($locale && $this->id){
            $translation = $this->translateOrOrigin($locale);
            if($translation){
                $translation->fill(request()->input());
                $res = $translation->save();
                if($res && $saveSeo){
                    $translation->saveSEO(request() , $locale);
                }
                return $res;
            }
        }

        return false;
    }

    public function fillData($attributes)
    {
        parent::fill($attributes);
    }

    public function fillByAttr($attributes , $input)
    {
        if(!empty($attributes)){
            foreach ( $attributes as $item ){
                $this->$item = isset($input[$item]) ? ($input[$item]) : null;
            }
        }
    }

    public function check_enable_review_after_booking(){

    }


    public static function getTableName()
    {
        return with(new static)->table;
    }

    public function hasPermissionDetailView(){
        if($this->status == "publish"){
            return true;
        }
        if(Auth::id() and $this->create_user == Auth::id() and Auth::user()->hasPermission('dashboard_vendor_access')){
            return true;
        }
        return false;
    }

    public function getImageUrlAttribute($size = "medium")
    {
        $url = FileHelper::url($this->image_id, $size);
        return $url ? $url : '';
    }

    public function wishlist(){
        return $this->hasOne(UserWishList::class, 'object_id')
            ->where('user_id', Auth::id())
            ->where('object_model', $this->type);
    }

    public function getForSitemap(){
        $all = parent::query()->where('status','publish')->get();
        $res = [];
        foreach ($all as $item){
            $res[] = [
                'loc'=>$item->getDetailUrl(),
                'lastmod'=>date('c',strtotime($item->updated_at ? $item->updated_at : $item->created_at)),
            ];
        }
        return $res;
    }

    public static function getTopCardsReport(){
        $user = Auth::user();
        if (empty($userId)) redirect()->to('login');
        $messages = \Modules\Core\Models\NotificationPush::query();
        if (is_admin()){
            $messages->where('data','like','%\"for_admin\":1%')->orWhere('notifiable_id', $user->id);
        } else {
            $messages->where('data','like','%\"for_admin\":0%')->where('notifiable_id', $user->id);
        }
        $totalMessages = $messages->count();
        $totalBookmark = UserWishList::where('user_id',$user->id)->count();

        if (is_candidate() && !is_admin()){
            $applied_job_total = JobCandidate::where('candidate_id',$user->id)->where('status','approved')->count();

            $res[] = [
                'size'   => 6,
                'size_md' => 3,
                'color' => '',
                'title'  => __("Jobs"),
                'amount' => $applied_job_total,
                'desc'   => __("Applied Jobs"),
                'class'  => 'purple',
                'icon'   => 'icon ion-ios-briefcase',
                'icon2'   => 'icon flaticon-briefcase'
            ];

        }

        if (is_employer()){
            $company_id = ($user->company) ? $user->company->id : '';
            $jobs = Job::query();
            if ($company_id) $jobs->where('company_id',$company_id);
            $jobs->where('create_user',Auth::id())->whereNull('company_id');
            $totalJob = $jobs->count();

            $totalApplication = JobCandidate::whereHas('jobInfo',function ($q) use($company_id){
                if( $company_id ) $q->where('company_id', $company_id);
            })->count();

            $res[] = [
                'size'   => 6,
                'size_md'=>3,
                'color' => '',
                'title'  => __("Applicants"),
                'amount' => $totalApplication ?? 0,
                'desc'   => __("Total Applicants"),
                'class'  => 'pink',
                'icon2'   => 'icon la la-user-friends',
                'icon'   => 'icon la la-user-friends'
            ];
        }

        $res[] = [

            'size'   => 6,
            'size_md'=> 3,
            'color' => 'ui-yellow',
            'title'  => __("Messages"),
            'amount' => $totalMessages,
            'desc'   => __("Total Messages"),
            'class'  => 'info',
            'icon'   => 'icon ion-md-chatboxes',
            'icon2'   => 'icon la la-comment-o'
        ];
        $res[] = [

            'size'   => 6,
            'size_md'=>3,
            'color' => 'ui-green',
            'title'  => __("Bookmark"),
            'amount' => $totalBookmark,
            'desc'   => __("Total Bookmark"),
            'class'  => 'success',
            'icon'   => 'icon ion-ios-heart',
            'icon2'   => 'icon la la-bookmark-o',
        ];
        if (is_candidate() && !is_admin()){
            $totalGig = Gig::where([
                'author_id'=>$user->id,
                'status'=>'publish'
            ])->count();
            $res[] = [
                'size'   => 6,
                'size_md' => 3,
                'color' => '',
                'title'  => __("Gig"),
                'amount' => $totalGig,
                'desc'   => __("Total Gig"),
                'class'  => 'pink',
                'icon'   => 'fa fa-gift pr-2',
                'icon2'   => 'icon la la-gifts'
            ];
        }
        return $res;
    }

    public static function getNotifications($limit = 10){
        $userId = Auth::id();
        if (empty($userId)) redirect()->to('login');
        $query = \Modules\Core\Models\NotificationPush::query();
        if (is_admin()){
            $query->where('data','like','%\"for_admin\":1%')->orWhere('notifiable_id', $userId);
        } else {
            $query->where('data','like','%\"for_admin\":0%')->where('notifiable_id', $userId);
        }
        $notifications = $query->orderBy('created_at','desc')->limit($limit)->get();
        if (empty($notifications)) return false;
        return $notifications;
    }

    public static function getDashboardChartData($from, $to){
        $data = [
            'labels'   => [],
            'datasets' => [
                [
                    'label' => "Views",
                    'backgroundColor' => 'transparent',
                    'borderColor' => '#1967D2',
                    'borderWidth' => "1",
                    'data' => [],
                    'pointRadius' => 3,
                    'pointHoverRadius' => 3,
                    'pointHitRadius' => 10,
                    'pointBackgroundColor' => "#1967D2",
                    'pointHoverBackgroundColor' => "#1967D2",
                    'pointBorderWidth' => "2"
                ]
            ]
        ];
        if (($to - $from) / DAY_IN_SECONDS > 90) {
            $year = date("Y", $from);
            // Report By Month
            for ($month = 1; $month <= 12; $month++) {
                $day_last_month = date("t", strtotime($year . "-" . $month . "-01"));
                if (is_admin()){
                    $view_order = Order::where('status','completed')->whereBetween('created_at', [
                        $year . '-' . $month . '-01 00:00:00',
                        $year . '-' . $month . '-' . $day_last_month . ' 23:59:59'
                    ])->count();
                } else {
                    $view_order = UserViews::where('user_id',Auth::id())->whereBetween('created_at', [
                        $year . '-' . $month . '-01 00:00:00',
                        $year . '-' . $month . '-' . $day_last_month . ' 23:59:59'
                    ])->count();
                }
                $data['labels'][] = date("F", strtotime($year . "-" . $month . "-01"));
                $data['datasets'][0]['data'][] = $view_order;
            }
        } elseif (($to - $from) <= DAY_IN_SECONDS) {
            // Report By Hours
            for ($i = strtotime(date('Y-m-d 00:00:00', $from)); $i <= strtotime(date('Y-m-d 23:59:59', $to)); $i += HOUR_IN_SECONDS) {
                if (is_admin()){
                    $view_order = Order::where('status','completed')->whereBetween('created_at', [
                        date('Y-m-d H:i:s', $i),
                        date('Y-m-d H:i:s', $i + HOUR_IN_SECONDS),
                    ])->count();
                } else {
                    $view_order = UserViews::where('user_id',Auth::id())->whereBetween('created_at', [
                        date('Y-m-d H:i:s', $i),
                        date('Y-m-d H:i:s', $i + HOUR_IN_SECONDS),
                    ])->count();
                }

                $data['labels'][] = date('H:i', $i);
                $data['datasets'][0]['data'][] = $view_order;
            }
        } else {
            for ($i = strtotime(date('Y-m-d', $from)); $i <= strtotime(date('Y-m-d 23:59:59', $to)); $i += DAY_IN_SECONDS) {
                if (is_admin()){
                    $view_order = Order::where('status','completed')->whereBetween('created_at', [
                        date('Y-m-d 00:00:00', $i),
                        date('Y-m-d 23:59:59', $i),
                    ])->count();
                } else {
                    $view_order = UserViews::where('user_id',Auth::id())->whereBetween('created_at', [
                        date('Y-m-d 00:00:00', $i),
                        date('Y-m-d 23:59:59', $i),
                    ])->count();
                }
                $data['labels'][] = display_date($i);
                $data['datasets'][0]['data'][] = $view_order;
            }
        }

        return $data;
    }
}
