<?php

namespace App\Models;

use App\Components\Functions;
use App\Events\HostelCreated;
use App\Events\LogAction;
use App\Jobs\CreateHostelConservationV2;
use App\Jobs\CreateHostelPostCrawl;
use App\Jobs\GenerateDynamicLinkHostel;
use App\Notifications\SendWhenConfirmHostel;
use App\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\Activitylog\Traits\LogsActivity;

class Hostel extends Model
{
    //
    use SoftDeletes;
    use LogsActivity;

    protected static $logAttributes = ['*'];

    const NOT_CONFIRM = 0;
    const CONFIRMED = 1;
    const WAIT_CONFIRM = 2;
    const CONFIRM_WRONG_DATA = 3;

    const ACTIVE = 1;
    const IN_ACTIVE = 0;

    const TYPE_RENT_ALL = 1;
    const TYPE_RENT_EVERY = 0;

    const SOURCE_USER = 0;
    const SOURCE_IMPORT = 1;
    const SOURCE_CRAWLER = 2;


    protected $fillable = [
        'name',
        'owner_id',
        'phone',
        'number_floors',
        'address',
        'lat',
        'lng',
        'province_id',
        'district_id',
        'ward_id',
        'number_rooms',
        'status',
        'status_confirm',
        'type',
        'electric_price',
        'water_price',
        'collaborator_id',
        'desc',
        'created_at',
        'updated_at',
        'deleted_at',
        'images',
        'image',
        'avg_ratings',
        'number_empty_room',
        'number_empty_rooms',
        'is_featured',
        'expire_featured',
        'owner_name',
        'owner_id_number',
        'owner_phone',
        'owner_email',
        'date_ew',
        'date_money',
        'type_rent',
        'source',
        'is_display',
        'hotline',
        'user_hotline',
        'smallest_price',
        // smallest và greatest để lưu giá trị min max mà chủ trọ nhập
        'greatest_price',
        'min_price',
        //min và max là 2 giá trị min max thực tế. Nếu ko có phòng thì nó là smallest và greatest. Nếu có phòng nó ăn theo giá phòng
        'max_price',
        'note',
        'is_verify',
        'sort_price',
        'dynamic_link',
        'number_beds'
    ];

    protected $dates = [
        'created_at',
        'updated_at',
        'deleted_at',
        'expire_featured'
    ];

    public static function boot()
    {
        parent::boot();

        static::saved(function ($item) {
            $userId = Functions::getCurrentUserId();
            //dispatch(new CreateHostelConservationV2($item->id, $userId));
        });

        static::deleted(function ($item) {
            HostelPostCrawl::query()
                ->where('hostel_id', $item->id)
                ->delete();

            $user = Functions::getCurrentUser();
            event(new LogAction([
                'type' => 'delete-hostel',
                'user_id' => optional($user)->id,
                'object_id' => $item->id,
                'hostel_id' => $item->id,
                'properties' => $item->toArray(),
                'desc' => '{'.$user->name.'} đã xóa nhà {'.$item->name.'}'
            ]));

        });

        static::creating(function ($item) {
            if (!is_null($item->smallest_price)) {
                $item->min_price = $item->smallest_price;
            }

            if (!is_null($item->greatest_price)) {
                $item->max_price = $item->greatest_price;
            }
        });

        static::updating(function ($item) {
            $numberRooms = Room::query()->where('hostel_id', $item->id)->count();
            if ($numberRooms == 0) {
                if (!is_null($item->smallest_price)) {
                    $item->min_price = $item->smallest_price;
                }
                if (!is_null($item->greatest_price)) {
                    $item->max_price = $item->greatest_price;
                }
            }

        });
        static::updated(function ($item) {

            if ($item->isDirty('status_confirm')) {
                $owner = $item->owner;
                if ($owner) {
                    $transaction = null;
                    if ($item->status_confirm == Hostel::CONFIRMED) {

                        User::query()
                            ->where('id', $owner->id)
                            ->where('type', User::OWNER)
                            ->update([
                                'refer_status' => User::REFER_STATUS_SUCCESS,
                                'refer_reason' => null
                            ]);

                        $transaction = \App\Models_v2\Transaction::query()
                            ->where('hostel_id', $item->id)
                            ->first();
                    }

                    $message = Functions::getNotificationConfirmText($item, $transaction);
                    \Notification::send($owner, new SendWhenConfirmHostel(
                        $item, $message
                    ));
                }
            }

            if ($item->status_confirm == Hostel::CONFIRMED) {
                $transaction = \App\Models_v2\Transaction::query()
                    ->where('status', \App\Models_v2\Transaction::STATUS_NOT_PROCESS)
                    ->where('hostel_id', $item->id)
                    ->first();
                if ($transaction) {
                    $transaction->status = \App\Models_v2\Transaction::STATUS_PROCESSED;
                    $transaction->save();
                    $user = $transaction->user;
                    if ($user) {
                        $user->increment('balance', $transaction->amount);
                    }
                    if ($transaction->achievement) {
                        $achievement = $transaction->achievement;
                        if ($achievement) {
                            $userAchievement = UserAchievement::query()
                                ->where('user_id', $transaction->user_id)
                                ->where('achievement_id', $achievement->id)
                                ->first();
                            if (!$userAchievement) {
                                $userAchievement = UserAchievement::create([
                                    'user_id' => $transaction->user_id,
                                    'achievement_id' => $achievement->id,
                                    'target' => $achievement->target,
                                    'done' => 0
                                ]);
                            }

                            $userAchievement->increment('done');
                        }
                    }
                }
            }

        });
        static::created(function ($item) {
            $checkConfirm = Hostel::withTrashed()
                ->where('owner_id', $item->owner_id)
                ->where('status_confirm', Hostel::CONFIRMED)
                ->count();
            $owner = $item->owner;
            if ($owner) {
                if ($checkConfirm == 0) {
                    if ($owner->refer_reason != User::REFER_REASON_CREATED_NOT_CONFIRM) {
                        User::query()
                            ->where('id', $owner->id)
                            ->where('type', User::OWNER)
                            ->update([
                                'refer_status' => User::REFER_STATUS_NOT_SUCCESS,
                                'refer_reason' => User::REFER_REASON_CREATED_NOT_CONFIRM
                            ]);
                    }
                }
            }

            $setting = Config::query()->first();
            if ($setting) {
                $configHostel = ConfigHostel::query()->where('hostel_id', $item->id)->first();
                if ($configHostel) {
                    if (empty($configHostel->contract)) {
                        $configHostel->contract = $setting->contract;
                        $configHostel->save();
                    }
                } else {
                    ConfigHostel::create([
                        'hostel_id' => $item->id,
                        'owner_id' => $item->owner_id,
                        'contract' => $setting->contract
                    ]);
                }
            }
            event(new HostelCreated($item));

            $owner = $item->owner;
            if ($owner) {
                $message = Functions::getNotificationConfirmText($item, null);
                \Notification::send($owner, new SendWhenConfirmHostel(
                    $item, $message
                ));
            }
//            $userId = Functions::getCurrentUserId();
//			dispatch(new CreateHostelConservationV2($item->id, $userId));




            $user = Functions::getCurrentUser();

            event(new LogAction([
                'type' => 'create-hostel',
                'user_id' => optional($user)->id,
                'object_id' => $item->id,
                'hostel_id' => $item->id,
                'properties' => $item->toArray(),
                'desc' => '{'.$user->name.'} đã tạo nhà {'.$item->name.'}'
            ]));

        });
    }

    public function staffHostels()
    {
        return $this->belongsToMany(User::class, 'staff_hostels', 'hostel_id', 'user_id');
    }


    public function deposits()
    {
        return $this->hasMany(Deposit::class)
            ->where(function($q) {
                $q->orHas('reserve');
                $q->orHas('contractValid');
            })->where(function($q) {
                $q->has('room');
            });
    }

    public function collectSpends()
    {
        return $this->hasMany(CollectSpend::class);
    }

    public function moneyInfos()
    {
        return $this->hasMany(MoneyInfo::class);
    }

    public function rooms()
    {
        return $this->hasMany(Room::class);
    }

    public function roomsEmpty()
    {
        return $this->hasMany(Room::class)->doesntHave('renters');
    }

    public function contracts()
    {
        return $this->hasMany(Contract::class);
    }

    public function contractValids()
    {
        return $this->hasMany(Contract::class)->where('status', '<>', Contract::LIQUIDATED);
    }

    public function ewMonth(Carbon $month)
    {
        return $this->hasMany(ElectricWater::class)->whereBetween('date_action',
            [
                $month->copy()->startOfMonth()->startOfDay()->toDateTimeString(),
                $month->copy()->endOfMonth()->endOfDay()->toDateTimeString()
            ]
        );
    }

    public function hostelType()
    {
        return $this->belongsTo('App\Models\HostelType', 'type', 'id');
    }

    public function getStatusConfirmTextAttribute()
    {
        if ($this->attributes['status_confirm'] == Hostel::NOT_CONFIRM) {
            return 'Chưa xác nhận';
        }

        if ($this->attributes['status_confirm'] == Hostel::WAIT_CONFIRM) {
            return 'Chờ xác nhận';
        }

        if ($this->attributes['status_confirm'] == Hostel::CONFIRMED) {
            return 'Đã xác nhận';
        }

        if ($this->attributes['status_confirm'] == Hostel::CONFIRM_WRONG_DATA) {
            return 'Thông tin sai thiếu';
        }

        return 'Chưa xác thực';
    }

    public function scopePublish($q)
    {
        return $q->where('status', Hostel::ACTIVE)->where('is_display', true);
    }

    public function scopeDisplay($q)
    {
        return $q->where('is_display', true);
    }

    public function getPriceTextAttribute()
    {
        $hostel = Hostel::find($this->attributes['id']);
        $price = Functions::getPriceHostelFrontend3($hostel);
        if (!empty($price)) {
            $smallest = $price['smallest'];
            $greatest = $price['greatest'];
            if (!empty($smallest) && !empty($greatest)) {
                if ($smallest == $greatest) {
                    return number_format($smallest, 0, '.', '.');
                }

                return number_format($smallest, 0, '.', '.') . '-' . number_format($greatest, 0, '.', '.');
            }

            if (!empty($smallest)) {
                return number_format($smallest, 0, '.', '.');
            }

            if (!empty($greatest)) {
                return number_format($greatest, 0, '.', '.');
            }
        }

        return 0;
    }

    public function getDescAttribute()
    {
        $desc = $this->attributes['desc'];

        return $desc;
        //return preg_replace("/\+?[0-9][0-9()\-.\s+]{7,20}[0-9]/", ' xxxxxxx ', $desc);
    }

    public function scopeFeatured($q)
    {
        return $q->where('is_featured', true)->where(function ($v) {
            $now = Carbon::now()->toDateString();
            $v->where('expire_featured', null);
            $v->orWhere('expire_featured', '>=', $now);
        });
    }

    public function owner()
    {
        return $this->belongsTo('App\User', 'owner_id', 'id');
    }

    public function collaborator()
    {
        return $this->belongsTo('App\User', 'collaborator_id', 'id');
    }

    public function ratings()
    {
        return $this->hasMany('App\Models\HostelRating')->orderBy('id', 'desc');
    }

    public function images()
    {
        return $this->hasMany(HostelImage::class, 'hostel_id', 'id');
    }

    public function videos()
    {
        return $this->hasMany(HostelVideo::class, 'hostel_id', 'id');
    }

    public function imagesMany()
    {
        return $this->hasMany(HostelImage::class, 'hostel_id', 'id');
    }

    public function amenities2()
    {
        return $this->belongsToMany(Amenity::class, 'hostel_amenities', 'hostel_id', 'amenities_id');
    }

    public function tags()
    {
        return $this->belongsToMany(Tag::class, 'hostel_tags', 'hostel_id', 'tag_id');
    }

    public function amenities()
    {
        return $this->hasMany('App\Models\Amenity')->orderBy('id', 'desc');
    }

    public function policies()
    {
        return $this->belongsToMany(Amenity::class, 'hostel_policies', 'hostel_id', 'policy_id');
    }


    public function scopeIsWithinMaxDistance($query, $coordinates, $radius = 15)
    {
        $haversine = "(6371 * acos(cos(radians(" . $coordinates['lat'] . ")) 
                    * cos(radians(`hostels`.`lat`)) 
                    * cos(radians(`hostels`.`lng`) 
                    - radians(" . $coordinates['lng'] . ")) 
                    + sin(radians(" . $coordinates['lat'] . ")) 
                    * sin(radians(`hostels`.`lat`))))";

        return $query->select('*')
            ->selectRaw("{$haversine} AS distance")
            ->whereRaw("{$haversine} < ?", [$radius]);
    }

    public function getStatusTextAttribute()
    {
        $status = $this->attributes['status'];

        if ($status == Hostel::ACTIVE) {
            return '<label class="label label-success">Kích hoạt</label>';
        } else if ($status == Hostel::IN_ACTIVE) {
            return '<label class="label label-danger">Chưa kích hoạt</label>';
        }

        return 'Chưa rõ';
    }

    public function getAddressAttribute()
    {
        if (str_contains(request()->fullUrl(), 'api/v1')) {

            if (!str_contains(request()->fullUrl(), 'hostel/detail')) {

                $addressDetail = $this->getAddressDetailAttribute();
                if (!empty($addressDetail)) {
                    return $this->attributes['address'] . ', ' . $addressDetail;
                }
            }
        }

        return $this->attributes['address'];
    }

    public function getAddressTextAttribute()
    {

        $addressDetail = $this->getAddressDetailAttribute();
        if (!empty($addressDetail)) {
            return $this->attributes['address'] . ', ' . $addressDetail;
        }


        return $this->attributes['address'];
    }

    public function getAddressDetailAttribute()
    {
        $district = $this->attributes['district_id'];
        $province = $this->attributes['province_id'];
        $ward = $this->attributes['ward_id'];
        $districtText = '';
        $provinceText = '';
        $wardText = '';

        if (!empty($district)) {
            $districtItem = Functions::getDistrictName($district);
            if ($districtItem) {
                $districtText = $districtItem->type.' '.$districtItem->name . ', ';
            }
        }

        if (!empty($province)) {
            $provinceItem = Functions::getProvinceName($province);
            if ($provinceItem) {
                $provinceText = $provinceItem->name;
            }
        }

        if (!empty($ward)) {
            $wardItem = Functions::getWardName($ward);
            if ($wardItem) {
                $wardText = $wardItem->type.' '.$wardItem->name . ', ';
            }
        }

        return trim($wardText . $districtText . $provinceText);
    }

    public function getImageAttribute()
    {
        $image = $this->attributes['image'];

        $images = \DB::table('hostel_images')->where('hostel_id', $this->attributes['id'])->first();
        if ($images) {
            return '/files/' . $images->image;
        }
        if (!str_contains(request()->fullUrl(), 'api/v1') && !str_contains(request()->fullUrl(), 'api/v2')) {
            return '/random/pic' . rand(1, 25) . '.jpg';
        }

        if (empty($image)) {
            return $image;
        }

        if (str_contains($image, 'http')) {
            return $image;
        }

        if (str_contains($image, '/files/')) {
            return '/files/' . str_replace('/files/', '', $image);
        }

        if (!str_contains($image, 'http') && !str_contains($image, '/files')) {
            return '/files/' . $image;
        }

        //  return $image;
    }

    public function getTypeRentTextAttribute()
    {
        $typeRent = $this->attributes['type_rent'];
        if ($typeRent == self::TYPE_RENT_EVERY) {
            return 'Ký túc xá';
        }

        return 'Bao phòng';
    }

    public function getHotlinePhoneAttribute()
    {
        if ($this->owner->id == 31746) { //chau anh
            return null;
        }
        if ($this->owner->id == 22509) { //nine housing
            return '0935988663';
        }
        if ($this->owner->id == 57225) { //chi vy
            return '0946376349';
        }
        if ($this->owner->phone == '0984558843') { //thland
            return '0393853456';
        }
        if ($this->owner->phone == '0909809001') { //thland
            return '0987386872';
        }
        if ($this->owner->phone == '0988885380') { //thland
            return '0982603861';
        }
        $hotline = $this->owner->phone;
        if (!empty($this->hotline)) {
            $hotline = $this->hotline;
        }

        return $hotline;
    }

    public function province()
    {
        return $this->belongsTo(Province::class, 'province_id', 'provinceid');
    }

    public function district()
    {
        return $this->belongsTo(District::class, 'district_id', 'districtid');
    }

    public function ward()
    {
        return $this->belongsTo(Ward::class, 'ward_id', 'wardid');
    }

    public function staffs()
    {
        return $this->belongsToMany(User::class, 'staff_hostels', 'hostel_id', 'user_id')->withTimestamps();
    }

    public function promotions()
    {
        return $this->belongsToMany(Promotion::class, 'hostel_promotions', 'hostel_id', 'promotion_id');
    }
}
