<?php

namespace App\Modules\Clients;

use App\Models\ValidationModel;
use App\Models\Follow;
use App\Models\Keychain;
use App\Modules\Bookings\Task;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use App\Modules\Invoices\Sale;
use App\Models\User;

class Customer extends ValidationModel
{
    use SoftDeletes;

    use \Venturecraft\Revisionable\RevisionableTrait;

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

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

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = ['sugarcrm_id'];

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

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

    /**
     * Array of validation rules.
     *
     * @var  array
     */
    protected static $rules = [
        'first_name' => ['required'],
        'last_name'  => ['required'],
    ];

    /**
     *	The attributes that won't be assigned during
     *	a mass assignment.
     */
    protected $fillable = [
        'first_name', 'last_name', 'email', 'date_of_birth', 'phone', 'phone2', 'mobile', 'address', 'address2', 'town', 'county', 'postcode', 'blind_notes', 'enable_feedback', 'sugarcrm_id', 'flagged', 'dynamics_id',
    ];

    /**
     *	Virtual Method: concatenates the first and the last name.
     */
    public function getNameAttribute(): string
    {
        return $this->first_name.' '.$this->last_name;
    }

    /**
     * Get the type attribute.
     */
    public function getTypeAttribute(): string
    {
        return 'customer';
    }

    /**
     * Returns the suggested user for this customer.
     */
    public function getSuggestedUserAttribute(): ?User
    {
        // Convert raw SQL to Laravel query builder
        $mostAssignedUser = Task::join('users', 'tasks.assigned_to', '=', 'users.id')
            ->select('assigned_to')
            ->selectRaw('COUNT(assigned_to) as count')
            ->where('users.active', 1)
            ->where('users.id', '!=', 1)
            ->where('client_type', 'customer')
            ->where('client_id', $this->id)
            ->whereNotNull('assigned_to')
            ->groupBy('assigned_to')
            ->orderByDesc('count')
            ->first();

        return $mostAssignedUser ? User::find($mostAssignedUser->assigned_to) : null;
    }

    /**
     * Get the address as a one line string.
     */
    public function getInlineAddressAttribute(): string
    {
        $address = [];
        if ($this->address) {
            $address[] = $this->address;
        }
        if ($this->address2) {
            $address[] = $this->address2;
        }
        if ($this->town) {
            $address[] = $this->town;
        }
        if ($this->county) {
            $address[] = $this->county;
        }
        if ($this->postcode) {
            $address[] = $this->postcode;
        }

        return implode(', ', $address);
    }

    /**
     * Follow a user for this customer.
     */
    public function follow(int $user_id): void
    {
        $follow = new Follow();
        $follow->user_id = $user_id;
        $follow->followable_id = $this->id;
        $follow->followable_type = 'App\Modules\Clients\Customer';
        $follow->save();
    }

    /**
     * Get all tasks for this customer (polymorphic relationship).
     *
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
     */
    public function tasks(): MorphMany
    {
        return $this->morphMany(Task::class, 'client', 'client_type', 'client_id');
    }

    /**
     * Get the keychains relationship.
     */
    public function keychains(): MorphMany
    {
        return $this->morphMany(Keychain::class, 'keychainable');
    }

    /**
     * Get all sales for this customer (polymorphic relationship).
     *
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
     */
    public function sales(): MorphMany
    {
        return $this->morphMany(Sale::class, 'client', 'client_type', 'client_id');
    }

    /**
     * Get all devices for this customer (polymorphic relationship).
     *
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
     */
    public function devices(): MorphMany
    {
        return $this->morphMany(\App\Modules\Bookings\Device::class, 'client', 'client_type', 'client_id');
    }

    /**
     * Get all projects for this customer (polymorphic relationship).
     *
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
     */
    public function projects(): MorphMany
    {
        return $this->morphMany(\App\Modules\Bookings\Project::class, 'client', 'client_type', 'client_id');
    }

    /**
     * Get all messages for this customer (polymorphic relationship).
     *
     * @return \Illuminate\Database\Eloquent\Relations\MorphMany
     */
    public function messages(): MorphMany
    {
        return $this->morphMany(\App\Modules\Bookings\Message::class, 'client', 'client_type', 'client_id');
    }

    /**
     * Search customers by a given term.
     */
    public function scopeSearch($query, string $term)
    {
        return $query->select('id', 'first_name', 'last_name', 'flagged')->whereNull('deleted_at')->where(function ($query) use ($term) {
                $query->where(\DB::raw("CONCAT_WS(' ', first_name, last_name)"), 'like', '%'.$term.'%')
                                ->orWhere('phone', 'like', $term.'%')
                                ->orWhere('phone2', 'like', $term.'%')
                                ->orWhere('mobile', 'like', $term.'%')
                                ->orWhere('email', 'like', '%'.$term.'%');
            });
    }

}
