<?php

namespace App\Models\Client;

use App\Casts\DOB;
use App\Casts\EmailAddress;
use App\Casts\PhoneNumber;
use App\Interface\AddressOwner;
use App\Interface\CallableEntity;
use App\Interface\DocumentOwner;
use App\Interface\HistoryOwner;
use App\Interface\NoteOwner;
use App\Models\Claim\Claim;
use App\Models\ContractRequest;
use App\Models\LeadSource\LeadSource;
use App\Models\PensionCase\PensionCase;
use App\Models\WillsCase\WillsCase;
use App\Models\LeadSource\LeadSourceEndpoint;
use App\Models\OptIn;
use App\Models\Relation;
use App\Models\Tranche;
use App\Trait\HasAddresses;
use App\Trait\HasDocuments;
use App\Trait\HasHistory;
use App\Trait\HasInteractions;
use App\Trait\HasName;
use App\Trait\HasNotes;
use App\Trait\HasSlug;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;

class Client extends Model implements DocumentOwner, NoteOwner, HistoryOwner, AddressOwner, CallableEntity {
    protected $table = 'clients';
    protected $fillable = [
        'slug',
        'reference',
        'title',
        'name_first',
        'name_middle',
        'name_last',
        'name_preferred',
        'date_of_birth',
        'phone_number',
        'email_address',
        'preferences',

        'lead_source_id',
        'lead_source_endpoint_id',
        'tranche_id',
    ];

    protected $casts = [
        'date_of_birth' => DOB::class,
        'phone_number' => PhoneNumber::class,
        'email_address' => EmailAddress::class,
        'preferences' => 'array',
    ];

    use HasName, HasSlug, HasNotes, HasDocuments, HasHistory, HasAddresses, SoftDeletes, HasFactory;

    public function executor() {
        return $this->hasOne(Executor::class);
    }

    public function previousNames() {
        return $this->hasMany(PreviousName::class);
    }

    public function claim(): HasOne {
        return $this->hasOne(Claim::class);
    }

    public function pensionCases(): HasMany {
        return $this->hasMany(PensionCase::class);
    }

    public function willsCases(): HasMany {
        return $this->hasMany(WillsCase::class);
    }

    public function leadSource() {
        return $this->belongsTo(LeadSource::class);
    }

    public function endpoint() {
        return $this->belongsTo(LeadSourceEndpoint::class, 'lead_source_endpoint_id');
    }

    public function relations() {
        return $this->hasMany(Relation::class);
    }

    public function optins() {
        return $this->belongsToMany(OptIn::class, 'client_optins');
    }

    public function tranche() {
        return $this->belongsTo(Tranche::class);
    }

    public function confirmIdentity() {
        return $this->hasOne(ConfirmIdentity::class);
    }

    public function handlers() {
        return $this->hasMany(ClientHandler::class);
    }

    public function contractRequests(): HasMany {
        return $this->hasMany(ContractRequest::class);
    }

    public function getDocumentStoragePath(): string {
        return 'clients/' . $this->slug . '/';
    }

    public function getPreferencesAttribute($value) {
        $defaults = [
            'home_address' => 0,
            'corp_address' => 0,
            'diff_format' => 0,
            'braille' => 0,
            'large_print' => 0,
            'audio' => 0,
            'other_lang' => 0,
        ];

        return array_merge($defaults, json_decode($value, true) ?: []);
    }

    public function getCallableNumber(): ?string {
        return (string)$this->phone_number;
    }

    public function getCallableLabel(): string {
        return $this->fullName;
    }

    public function getCallableType(): string {
        return 'client';
    }

    protected function displayId(): Attribute {
        return Attribute::make(
            get: fn() => 1 . str_pad($this->id, 5, '0', STR_PAD_LEFT),
        );
    }
}
