<?php

namespace App\Modules\Bookings;

use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;
use App\Modules\Notifications\Notification;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Modules\Gamification\PointsTrait;
use App\Modules\Bookings\Traits\TaskAutomationTrait;
use App\Modules\Bookings\Traits\RepairAntivirusState;
use Venturecraft\Revisionable\RevisionableTrait;
use App\Models\ValidationModel;
use App\Modules\Bookings\Project;
use App\Modules\Bookings\Comment;
use App\Modules\Bookings\MobileToken;
use App\Modules\Bookings\StatusChange;
use App\Models\AssignedChange;
use App\Models\StandardPrice;
use App\Modules\Bookings\TaskFeedback;
use App\Modules\Bookings\Device;
use App\Modules\Bookings\Subtype;
use App\Modules\Bookings\Task as TaskModel;
use App\Modules\Clients\Client;
use App\Modules\Clients\Customer;
use App\Modules\Clients\Site;
use App\Modules\Clients\SiteUser;
use App\Models\User;
use App\Modules\Invoices\Sale;
use App\Models\Severity;
use App\Modules\Bookings\Part;
use App\Modules\Bookings\Build;
use App\Modules\Bookings\CustomerNotification;
use App\Modules\Bookings\Template;
use App\Modules\Bookings\TemplateItem;
use App\Models\Status;
use App\Models\Keychain;
use Illuminate\Support\Facades\DB;

class Task extends ValidationModel
{
    use SoftDeletes;
    use PointsTrait;
    use TaskAutomationTrait;
    use RevisionableTrait;
    use RepairAntivirusState;

    /**
     * A presenter to format the properties in the view.
     */
    protected $presenter = 'App\Modules\Bookings\TaskPresenter';

    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'tasks';

    /**
     * The name used in polimorphisms.
     *
     * @var string
     */
    protected $morphClass = 'task';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['title', 'problem', 'return_id', 'booking_fee_id', 'client_id', 'client_type', 'site_id', 'site_user_id', 'direct_dial', 'assigned_to', 'status_id', 'time_spent', 'severity_id', 'type', 'subtype_id', 'project_id', 'prebook', 'prebook_date', 'onsite_start', 'onsite_end', 'order_task_id', 'labour', 'needs_delivery', 'delivered_by', 'pin', 'paid', 'paid_at', 'invoiced', 'invoiced_at', 'invoice_number', 'delivered', 'needs_pickup', 'pickup_by', 'pickup_schedule', 'picked_up_at', 'standard_price_id', 'auto_booked', 'exchange_id', 'no_price_reason', 'nopassword_reason', 'shelf_type', 'shelf','followup_id','qa_id','passed_qa', 'satisfied_client', 'needs_calling', 'cancelled_reason', 'attended_time', 'unattended_time', 'formatedTimeSpent', 'formatedAttendedTime', 'formatedUnattendedTime', 'alarm_date', 'due_date', 'antivirus_state','recurring'];

    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = ['user_subscribed', 'points', 'formatedAttendedTime', 'formatedUnattendedTime', 'formatedProblemLimited', 'formatedProblem', 'formatedTimeSpent'];

    /**
     * The attributes that should be mutated to dates.
     *
     * @var array
     */
    protected $dates = ['deleted_at'];

    /**
     * The relations to eager load on every query.
     *
     * @var array
     */
    protected $with = ['status', 'feedback', 'passwords', 'standard_price', 'subscribed_user'];

    /**
     * The fields can be used in the events requirements.
     *
     * @var array
     */
    protected $event_fields = ['status'];

    /**
     * Retrieves a list of shelf types.
     *
     * @return array
     */
    public static function getShelfTypes()
    {
        return [
            '1' => 'Cabinet A',
            '2' => 'Cabinet B',
            '3' => "Cabinet C",
        ];
    }

    /**
     * Format the prebook_date, before setting it on the model.
     *
     * @param string $value
     *
     * @return null
     */
    public function setPrebookDateAttribute($value)
    {
        $value = floatval(strtotime($value));
        $this->attributes['prebook_date'] = ($value > 0) ? date('Y-m-d H:i:s', $value) : null;
    }

    /**
     * Format the prebook date when retrieved from the database.
     *
     * @param datetime|string $value
     *
     * @return string
     */
    public function getPrebookDateAttribute($value)
    {
        return date('d-m-Y', strtotime($value));
    }

    /**
     * Automatically convert any non existing value such as 0 to null.
     *
     * @param int $value
     *
     * @return string
     */
    public function setInvoiceNumberAttribute($value)
    {
        $this->attributes['invoice_number'] = ($value) ? $value : null;
    }

    /**
     * Format the date to not include hours and minutes.
     *
     * @return string
     */
    public function getPaidAtAttribute()
    {
        if (! isset($this->attributes['paid_at'])) {
            return;
        }

        return date('Y-m-d', strtotime($this->attributes['paid_at']));
    }

    /**
     * Parses the value passed to the paid_at attribute as a date
     * and formats it to MySQL standards.
     *
     * @param string $value
     *
     * @return null
     */
    public function setPaidAtAttribute($value)
    {
        $this->attributes['paid_at'] = Carbon::parse($value)->toDateTimeString();
    }

    /**
     * Returns only the subscribers that are the logged in user for the task.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function subscribed_user()
    {
        return $this->subscribers()->where('user_id', getAuthUserId());
    }

    /**
     * Determines if the logged in user is subscribed or not.
     *
     * @return bool
     */
    public function getUserSubscribedAttribute()
    {
        return $this->subscribed_user->count() ? true : false;
    }

    /**
     * Return the attended_time with format.
     *
     * @return string
     */
    public function getFormatedAttendedTimeAttribute()
    {
        return $this->shortFormatTime($this->attended_time);
    }

    /**
     * Return the unattended_time with format.
     *
     * @return string
     */
    public function getFormatedUnattendedTimeAttribute()
    {
        return $this->shortFormatTime($this->unattended_time);
    }

    /**
     * Sets the attended_time from formated time.
     *
     * @param string $formatedTime
     *
     * @return bool
     */
    public function setFormatedAttendedTimeAttribute($formatedTime)
    {
        $this->attended_time = dhm_to_seconds($formatedTime);
    }

    /**
     * Sets the unattended_time from formated time.
     *
     * @param string $formatedTime
     *
     * @return bool
     */
    public function setFormatedUnattendedTimeAttribute($formatedTime)
    {
        $this->unattended_time = dhm_to_seconds($formatedTime);
    }

    /**
     * Return the time_spent with format.
     *
     * @return string
     */
    public function getFormatedTimeSpentAttribute()
    {
        if (!$this->time_spent) {
            return '0m';
        }
        
        // Convert minutes to formatted time
        $minutes = intval($this->time_spent);
        
        if ($minutes < 60) {
            return $minutes . 'm';
        } else {
            $hours = intval($minutes / 60);
            $remainingMinutes = $minutes % 60;
            
            if ($remainingMinutes == 0) {
                return $hours . 'h';
            } else {
                return $hours . 'h ' . $remainingMinutes . 'm';
            }
        }
    }

    /**
     * Sets the time_spent from formated time.
     *
     * @param string $formatedTime
     *
     * @return bool
     */
    public function setFormatedTimeSpentAttribute($formatedTime)
    {
        // Convert formatted time to minutes
        $this->time_spent = $this->dhm_to_minutes($formatedTime);
    }

    /**
     * Converts the given days / hours / minutes string to minutes.
     *
     * @param string $formatedTime
     *        eg: 5d 3h 2m or 10m or 2h
     *
     * @return integer
     */
    protected function dhm_to_minutes($formatedTime)
    {
        if (empty($formatedTime)) {
            return 0;
        }
        
        // Handle numeric input without suffix (assume minutes)
        if (is_numeric($formatedTime)) {
            return intval($formatedTime);
        }
        
        $splited = explode(' ', $formatedTime);
        $minutes = 0;

        for ($i = 0; $i < count($splited); $i++) {
            $num = 0;
            
            if (strpos($splited[$i], 'd') !== false) {
                $num = intval(str_replace('d', '', $splited[$i]));
                $num = $num * 1440; // minutes per day
            } elseif (strpos($splited[$i], 'h') !== false) {
                $num = intval(str_replace('h', '', $splited[$i]));
                $num = $num * 60; // minutes per hour
            } elseif (strpos($splited[$i], 'm') !== false) {
                $num = intval(str_replace('m', '', $splited[$i]));
                // Already in minutes
            } else {
                // No suffix, assume minutes
                $num = intval($splited[$i]);
            }

            $minutes = $minutes + $num;
        }

        return $minutes;
    }

    /**
     * Returns the client model.
     *
     * @return App\Modules\Clients\Client or App\Modules\Clients\Customer depending on type.
     */
    /**
     * Boot the model and set up the morphMap
     */
    public static function boot()
    {
        parent::boot();
        
        // Set up morphMap for all polymorphic relationships
        \Illuminate\Database\Eloquent\Relations\Relation::morphMap([
            'client' => Client::class,
            'customer' => Customer::class,
            'task' => self::class,
        ]);
        
        // Register the task completion observer for SMS notifications
        self::observe(\App\Modules\Bookings\events\TaskCompletionObserver::class);
    }
    
    public function client()
    {
        // Use morphTo with proper class mapping
        return $this->morphTo('client', 'client_type', 'client_id');
    }

    /**
     * Automatically set assigned_to to null if it's empty or 0.
     *
     * @param int $value
     *
     * @return null
     */
    public function setAssignedToAttribute($value)
    {
        if (! $value || empty($value) || $value == '0') {
            $this->attributes['assigned_to'] = null;
        } else {
            $this->attributes['assigned_to'] = intval($value);
        }
    }

    /**
     * Returns the site associated with this task. This only applies to business customers.
     *
     * @return App\Modules\Clients\Site
     */
    public function site()
    {
        return $this->belongsTo(Site::class, 'site_id');
    }

    /**
     * Returns the site user model.
     *
     * @return App\Modules\Clients\SiteUser
     */
    public function site_user()
    {
        return $this->belongsTo(SiteUser::class, 'site_user_id');
    }

    /**
     * Returns the sale that contains the booking fee.
     *
     * @return App\Modules\Invoices\Sale
     */
    public function booking_fee()
    {
        return $this->belongsTo(Sale::class, 'booking_fee_id');
    }

    /**
     * Returns the severity model.
     *
     * @return \Severity
     */
    public function severity()
    {
        return $this->belongsTo(Severity::class, 'severity_id');
    }

    /**
     * Returns the user who created the task.
     *
     * @return \User
     */
    public function creator()
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    /**
     * Returns the user who updated the task.
     *
     * @return \User
     */
    public function modifier()
    {
        return $this->belongsTo(User::class, 'updated_by');
    }

    /**
     * Returns the user who this task is assigned to.
     *
     * @return \User
     */
    public function user()
    {
        return $this->belongsTo(User::class, 'assigned_to');
    }

    /**
     * Returns all the comments for a particular task.
     *
     * @return App\Modules\Bookings\Comment
     */
    public function comments()
    {
        return $this->hasMany(Comment::class, 'related_id')->where('related_type', '=', 'task');
    }
    
    /**
     * Returns all tokens for the repair
     *
     * @return App\Modules\Bookings\MobileToken
     */
    public function mobile_tokens()
    {
        return $this->hasMany(MobileToken::class, 'related_id')->where('related_type', '=', 'task');
    }

    /**
     * Returns all the comments for a particular task.
     *
     * @return App\Modules\Bookings\Comment
     */
    public function publicComments()
    {
        return $this->hasMany(Comment::class, 'related_id')->where('related_type', '=', 'task')->where('public', 1);
    }

    /**
     * Returns all the parts for a particular task.
     *
     * @return App\Modules\Bookings\Part
     */
    public function parts()
    {
        return $this->morphMany(Part::class, 'related');
    }

    /**
     * Returns all the parts for a particular task.
     *
     * @return App\Modules\Bookings\Part
     */
    public function builds()
    {
        return $this->morphMany(Build::class, 'related');
    }

    /**
     * Returns all the notifications sent to the customer related to this task.
     *
     * @return App\Modules\Bookings\CustomerNotification
     */
    public function customer_notifications()
    {
        return $this->hasMany(CustomerNotification::class, 'task_id');
    }

    /**
     * Returns the project associated with this task.
     *
     * @return App\Modules\Bookings\Project
     */
    public function project()
    {
        return $this->belongsTo(Project::class, 'project_id');
    }

    /**
     * Returns all the templates for a particular task.
     *
     * @return App\Modules\Bookings\Template
     */
    public function templates()
    {
        return $this->belongsToMany(Template::class, 'task_templates', 'task_id', 'template_id');
    }

    /**
     * Returns all the completed and not required task items.
     *
     * @return App\Modules\Bookings\TemplateItem
     */
    public function template_items()
    {
        return $this->belongsToMany(TemplateItem::class, 'task_template_items', 'task_id', 'template_item_id')->withPivot('value');
    }

    /**
     * Returns all the completed task items.
     *
     * @return App\Modules\Bookings\TemplateItem
     */
    public function completed_template_items()
    {
        return $this->belongsToMany(TemplateItem::class, 'task_template_items', 'task_id', 'template_item_id')->withPivot('value')->where('value', 1);
    }

    /**
     * Returns the status for this task.
     *
     * @return \Status
     */
    public function status()
    {
        return $this->belongsTo(Status::class, 'status_id');
    }

    /**
     * Returns all the related tasks.
     *
     * @return Illuminate\Support\Collection
     */
    public function related_tasks()
    {
        return $this->belongsToMany(TaskModel::class, 'related_tasks', 'task_id', 'related_task_id')->withTimestamps();
    }

    /**
     * Returns the followed tasks.
     *
     * @return Illuminate\Support\Collection
     */
    public function followup_task()
    {
        return $this->hasMany(TaskModel::class, 'followup_id');
    }

    /**
     * Returns all the qas done for this task.
     *
     * @return \Illuminate\Support\Collection
     */
    public function qa_tasks()
    {
        return $this->hasMany(TaskModel::class, 'qa_id');
    }

    /**
     *Involved members staff in this task.
     */
    public function involved_users()
    {
        // Add the user that created the task
        $users = [];
        if ($this->creator) {
            $users[] = $this->creator;
        }

        $inArray = function ($user_or_id, $users) {
            // Handle both User object and user ID
            $id = is_object($user_or_id) ? $user_or_id->id : $user_or_id;

            foreach ($users as $user) {
                // Handle case where $user might be null, an integer, or an object
                if (is_object($user) && isset($user->id) && $user->id == $id) {
                    return true;
                } elseif (is_int($user) && $user == $id) {
                    return true;
                }
            }

            return false;
        };

        // Add all the users that have had the task assigned to them if they weren't already
        foreach ($this->assigned_changes()->with('new_user')->get() as $i => $change) {
            if ($change->new_user) {
                // Ensure we have a User object, not just an ID
                $userObject = is_object($change->new_user) ? $change->new_user : User::find($change->new_user);
                if ($userObject && ! $inArray($userObject, $users)) {
                    array_push($users, $userObject);
                }
            }
        }

        //Add all the users that have had any qa for this task assigned to them if they weren't already there
        foreach ($this->qa_tasks()->with('assigned_changes')->get() as $qa) {
            foreach ($qa->assigned_changes()->with('new_user')->get() as $change) {
                if ($change->new_user) {
                    // Ensure we have a User object, not just an ID
                    $userObject = is_object($change->new_user) ? $change->new_user : User::find($change->new_user);
                    if ($userObject && ! $inArray($userObject, $users)) {
                        array_push($users, $userObject);
                    }
                }
            }
        }

        return $users;
    }

    /**
     * Retrieves all the status changes for a particular task.
     *
     * @return \Illuminate\Support\Collection
     */
    public function status_changes()
    {
        return $this->hasMany(StatusChange::class, 'related_id')->where('related_type', '=', 'task');
    }

    /**
     * Retrieves all the assigned changes for a particular task.
     *
     * @return \Illuminate\Support\Collection
     */
    public function assigned_changes()
    {
        return $this->hasMany(AssignedChange::class, 'related_id')->where('related_type', '=', 'task');
    }

    /**
     * Returns the standard price details for this task.
     *
     * @return \StandardPrice
     */
    public function standard_price()
    {
        return $this->belongsTo(StandardPrice::class, 'standard_price_id');
    }

    /**
     * Returns the feedback for this task.
     *
     * @return App\Modules\Bookings\TaskFeedback
     */
    public function feedback()
    {
        return $this->hasOne(TaskFeedback::class, 'task_id');
    }

    /**
     * Returns all the devices that have this repair.
     *
     * @return \App\Modules\Bookings\Device
     */
    public function devices()
    {
        return $this->belongsToMany(Device::class, 'task_devices', 'task_id');
    }

    /**
     * Returns the total price for all the parts assigned to this task.
     *
     * @return float
     */
    public function getPartsTotalAttribute()
    {
        $total = $this->parts()->select(DB::raw('SUM(parts.quantity * parts.price * (parts.vat / 100 + 1)) as total'))->first();

        return floatval($total->total);
    }

    /**
     * Return the subtype for the task.
     *
     * @return App\Modules\Bookings\Subtype
     */
    public function subtype()
    {
        return $this->belongsTo(Subtype::class, 'subtype_id');
    }

    /**
     * Retrieves a list of subscribers.
     *
     * @return Illuminate\Support\Collection
     */
    public function subscribers()
    {
        return $this->belongsToMany(User::class, 'task_subscribers', 'task_id')->withTimestamps();
    }

    /**
     * Returns the password associated with the task.
     *
     * @return \Keychain
     */
    public function passwords()
    {
        return $this->belongsToMany(Keychain::class, 'task_keychains', 'task_id', 'keychain_id');
    }

    /**
     * Restrict query to unassigned.
     */
    public function scopeUnassigned($query)
    {
        return $query->whereNull('assigned_to');
    }

    /**
     * Restrict query to unassigned.
     */
    public function scopeSortid($query)
    {
        return $query->orderBy('id', 'DESC');
    }

    /**
     * Restrict query to own tasks.
     */
    public function scopeOwn($query)
    {
        return $query->where('assigned_to', '=', Auth::user()->id);
    }

    /**
     * Restrict query to completed tasks.
     *
     * @return query
     */
    public function scopeCompletedStats($query)
    {
        return $query->where('tasks.completed', '=', 1)->where('tasks.status_id', '!=', 26)->where('tasks.status_id', '!=', 8);
    }

    /**
     * Restrict query to completed tasks.
     *
     * @return query
     */
    public function scopeCompleted($query)
    {
        return $query->where('tasks.completed', '=', 1);
    }

    /**
     * Restrict query to open tasks.
     *
     * @return query
     */
    public function scopeOpen($query)
    {
        return $query->where('tasks.completed', '=', 0);
    }

    /**
     * Restrict query to open tasks.
     *
     * @return query
     */
    public function scopeSupport($query)
    {
        return $query->where('tasks.type', 'support');
    }

    /** nadeem 28.2.17 for mattermost /repair command
     * Restrict query to open tasks.
     *
     * @return query
     */
    public function scopeRepair($query)
    {
      // die ("hit scopeRepair");
        return $query->where('tasks.type', 'repair');
    }
    /**
     * Filter tasks to unpaid.
     *
     * @return Query
     */
    public function scopeUnpaid($query)
    {
        return $query->completed()->where('tasks.paid', '=', 0);
    }

    /**
     * Filter tasks to paid.
     *
     * @return Query
     */
    public function scopePaid($query)
    {
        return $query->completed()->where('tasks.paid', '=', 1);
    }

    /************************** dec 2016  nadeem /tasks radio buttons fix  ******************************/

    public function scopeMyPaidAndUnpaid($query)
    {
         return $query->where('tasks.paid', '=', null);//->where('tasks.paid', '=', 1);
    }

    public function scopeMyPaid($query)
    {
         return $query->where('tasks.paid', '=', 1);
    }

    public function scopeMyUnpaid($query)
    {
         return $query->where('tasks.paid', '=', 0);
    }

        public function scopeMyCompletedAndOpen($query)
    {
         return $query->where('tasks.completed', '=', null);//->where('tasks.completed', '=', 1);
    }

    public function scopeMyCompleted($query)
    {
         return $query->where('tasks.completed', '=', 1);//->where('tasks.status_id', '!=', 9);
    }

    public function scopeMyOpen($query)
    {
         return $query->where('tasks.completed', '=', 0)->where('tasks.status_id', '!=', 9);
    }

 /************************** end /tasks radio buttons fix  ******************************/

    /**
     * Filter tasks to not invoiced.
     *
     * @return Query
     */
    public function scopeNotInvoiced($query)
    {
        return $query->completed()->where('tasks.invoiced', '=', 0);
    }

    /**
     * Filters results to todays date.
     *
     * @return Query
     */
    public function scopeToday($query)
    {
        return $query->whereDate('completed_at', today());
    }

    /**
     * Filters results to yesterday's date.
     *
     * @return Query
     */
    public function scopeYesterday($query)
    {
        return $query->whereDate('completed_at', yesterday());
    }

    /**
     * Filters results to this weeks interval date.
     *
     * @return Query
     */
    public function scopeThisWeek($query)
    {
        return $query->whereBetween('completed_at', [
            now()->startOfWeek(),
            now()->endOfWeek()
        ]);
    }

    /**
     * Filters results to last weeks interval date.
     *
     * @return Query
     */
    public function scopeLastWeek($query)
    {
        return $query->whereBetween('completed_at', [
            now()->subWeek()->startOfWeek(),
            now()->subWeek()->endOfWeek()
        ]);
    }

    /**
     * Filters results to this months interval date.
     *
     * @return Query
     */
    public function scopeThisMonth($query, $start_date = '', $end_date = '')
    {
        if ($start_date && $end_date) {
            $start_date = is_numeric($start_date) ? 
                now()->setTimestamp($start_date)->startOfDay() : 
                now()->parse($start_date)->startOfDay();
            $end_date = is_numeric($end_date) ? 
                now()->setTimestamp($end_date)->endOfDay() : 
                now()->parse($end_date)->endOfDay();

            return $query->whereBetween('tasks.completed_at', [$start_date, $end_date]);
        }

        return $query->whereBetween('tasks.completed_at', [
            now()->startOfMonth(),
            now()->endOfMonth()
        ]);
    }

    /**
     * Filters results to this months interval date using the created_at field.
     *
     * @return Query
     */
    public function scopeCreatedThisMonth($query, $start_date = '', $end_date = '')
    {
        if ($start_date && $end_date) {
            $start_date = is_numeric($start_date) ? 
                now()->setTimestamp($start_date) : 
                now()->parse($start_date);
            $end_date = is_numeric($end_date) ? 
                now()->setTimestamp($end_date) : 
                now()->parse($end_date);

            return $query->whereBetween('created_at', [$start_date, $end_date]);
        }

        return $query->whereBetween('created_at', [
            now()->startOfMonth(),
            now()->endOfMonth()
        ]);
    }

    /**
     * Filters results to last months interval date.
     *
     * @return Query
     */
    public function scopeLastMonth($query)
    {
        return $query->whereBetween('completed_at', [
            now()->subMonth()->startOfMonth(),
            now()->subMonth()->endOfMonth()
        ]);
    }

    /**
     * Retrict the results to a given overdue period. Default 28 days.
     *
     * @return Query
     */
    public function scopeOverdue($query, $days = 28)
    {
        return $query->where('completed_at', '<', Carbon::now()->subDays($days)->toDateTimeString());
    }

    /**
     * Search customers by a given term.
     *
     * @param  $query
     * @param  $term
     *
     * @return Illuminate\Database\Query\Builder
     */
    public function scopeSearch($query, $term, $type = 'repair')
    {
        return $query->select('id', 'title', 'client_id', 'client_type')->where('type', $type)->where('tasks.id', 'like', $term.'%');
    }

    /**
     * Adds the feedback to the email queue. This should be called
     * once the job has been marked as completed.
     *
     * @return bool
     */
    public function registerFeedback()
    {
        $types = ['repair', 'support', 'onsite'];

        // Check to see if the customer can be sent the feedback form
        if ($this->client->enable_feedback && array_search($this->type, $types) !== false
                && $this->status_id != Status::TASKS_CANCELLED && $this->status_id != Status::TASKS_DUPLICATE) {
            // Check to see if feedback already exists for this job
            if (! $this->feedback && $this->assigned_to) {
                $feedback = TaskFeedback::create([
                    'task_id' => $this->id,
                    'user_id' => $this->assigned_to,
                    'code'    => str_random(32),
                    'reminder_sent' => 0,
                ]);

                return (! $feedback->exists) ? false : true;
            }
        }

        return false;
    }

    /**
     * Suggest the user that should take the job. This is calculated based on the previous history.
     *
     * @return bool
     */
    public function suggestUser()
    {
        $user = ($this->client) ? $this->client->suggested_user : false;

        if ($user) {
            // Send a notification
            $notification = Notification::create([
                'user_id'      => $user->id,
                'related_type' => $this->type,
                'related_id'   => $this->id,
                'message'      => 'New ' . ucfirst($this->type) . ' #' . $this->id . ' suggested: "' . $this->title . '"',
            ]);

            return ($notification->exists) ? true : false;
        }

        return false;
    }

    /**
     * Suggest the user that should take the job. This is calculated based on the previous history.
     *
     * @return bool
     */
    public function suggestQAUser()
    {
        $previous_qa = self::where('type', 'qa')->where('qa_id', $this->qa_id)->whereNotNull('assigned_to')->orderBy('completed_at', 'DESC')->first();

        if (! $previous_qa) {
            return false;
        }

        // Send a notification
        $notification = Notification::create([
            'user_id'      => $previous_qa->assigned_to,
            'related_type' => $this->type,
            'related_id'   => $this->id,
            'message'      => 'New QA ' . ucfirst($this->type) . ' #' . $this->id . ' suggested: "' . $this->title . '"',
        ]);
    }

    /**
     * Suggest the user that should take the job. This is calculated based on the previous history.
     *
     * @return bool
     */
    public function suggestFollowupUser()
    {
        $previous_followup = self::where('type', 'followup')->where('followup_id', $this->followup_id)->whereNotNull('assigned_to')->orderBy('completed_at', 'DESC')->first();

        if (! $previous_followup) {
            return false;
        }

        // Send a notification
        $notification = Notification::create([
            'user_id'      => $previous_followup->assigned_to,
            'related_type' => $this->type,
            'related_id'   => $this->id,
            'message'      => 'New followup ' . ucfirst($this->type) . ' #' . $this->id . ' suggested: "' . $this->title . '"',
        ]);
    }
    public function getLengthAttribute()
    {
        $dt1 = new Carbon($this->onsite_start);
        $dt2 = new Carbon($this->onsite_end);
        return  $dt2->diffInHours($dt1);
    }
    /**
     * Check if the templates associate to this
     * task have been fill completely.
     *
     * @return bool
     */
    public function completedTemplates()
    {
        $templates = $this->templates;

        foreach ($templates as $template) {
            $numItems = $this->template_items()->wherePivot('template_id', $template->id)->count();

            if ($numItems != $template->items()->count()) {
                return false;
            }
        }

        return true;
    }

    /**
     * Format time in seconds to short format (e.g., 1d 2h 30m)
     *
     * @param int $seconds
     * @return string
     */
    public function shortFormatTime($seconds)
    {
        if (!$seconds) {
            return '';
        }

        $toPrint = '';
        $DAY = 86400;
        $HOUR = 3600;
        $MINUTE = 60;

        if ($seconds / $DAY >= 1) {
            $toPrint .= floor($seconds / $DAY).'d';
            $seconds = $seconds % $DAY;
        }

        if ($seconds / $HOUR >= 1) {
            $toPrint .= ($toPrint ? ' ' : '').floor($seconds / $HOUR).'h';
            $seconds = $seconds % $HOUR;
        }

        if ($seconds / $MINUTE >= 1) {
            $toPrint .= ($toPrint ? ' ' : '').floor($seconds / $MINUTE).'m';
            $seconds = $seconds % $MINUTE;
        }

        return $toPrint;
    }

    /**
     * Get formatted problem text with limited length for confirmation sheets
     *
     * @return string
     */
    public function getFormatedProblemLimitedAttribute()
    {
        $text = strip_tags($this->problem, '<br><br/>');
        return strlen($text) > 650 ? substr($text, 0, 420).'...' : $text;
    }

    /**
     * Get formatted problem text with basic HTML tags preserved
     *
     * @return string
     */
    public function getFormatedProblemAttribute()
    {
        return strip_tags($this->problem, '<br><br/>');
    }
}
