<?php

namespace App\Models;

use App\Builders\MemberBuilder;
use App\Traits\Blameable;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Member extends Model
{
    use HasFactory, SoftDeletes, Blameable;

    protected $fillable = [
        "id",
        "person_id",
        "member_id",
        "record_type",
        "payor_id",
        "user_id",
        "name_prefix",
        "name",
        "name_suffix",
        "birth_date",
        "gender",
        "language",
        "race",
        "marital_status",
        "principal_id",
        "relation_with_principal",
        "bpjs_class",
        "active",
        "created_by",
        "updated_by",
        "deleted_by",

        "nric",
        "email",
        "bank_info",
        "agent_code",
        "address1",
        "address2",
        "address3",
        "address4",
        "city",
        "state",
        "postal_code",
        "passport_no",
        "passport_country",
        "identification_code",
        "pre_existing",
        "bpjs_id",
        "endorsement_date",
        "remarks",
        "policy_in_force",
        "start_no_claim",
        "end_no_claim",
    ];

    protected $appends = [
        'full_name',
        'age',
        'gender_code',
    ];

    protected $hidden = [
        'created_at',
        'updated_at',
        'deleted_at',
        'created_by',
        'updated_by',
        'deleted_by',
    ];

    public static function query(): MemberBuilder
    {
        return parent::query();
    }

    public function newEloquentBuilder($query): MemberBuilder
    {
        return new MemberBuilder($query);
    }

    /* -------------------------------------------------------------------------- */
    /*                                relationship                                */
    /* -------------------------------------------------------------------------- */
    public function claims()
    {
        return $this->hasMany(Claim::class, 'member_id', 'id');
    }

    public function postponedClaims()
    {
        return $this->hasMany(Claim::class, 'member_id', 'id')->where('status', 'postpone');
    }

    public function person()
    {
        return $this->belongsTo(Person::class, 'person_id', 'id');
    }

    public function employeds()
    {
        return $this->hasMany(CorporateEmployee::class, 'member_id');
    }

    public function corporates()
    {
        return $this
            ->belongsToMany(Corporate::class, 'corporate_employees', 'corporate_id', 'member_id')
            ->withPivot([
                'branch_code',
                'division_id',
                'nik',
                'status',
                'start',
                'end'
            ]);
    }

    public function currentCorporate()
    {
        return $this->hasOneThrough(Corporate::class, CorporateEmployee::class, 'member_id', 'id', 'id', 'corporate_id');
    }

    public function memberPlans()
    {
        return $this->hasMany(MemberPlan::class, 'member_id');
    }

    public function plans()
    {
        return $this->hasManyThrough(Plan::class, MemberPlan::class, 'member_id', 'id', 'id', 'plan_id');
    }

    public function currentPlan()
    {
        return $this->hasOneThrough(Plan::class, MemberPlan::class, 'member_id', 'id', 'id', 'plan_id')
            ->latest(); // TODO Fix This
    }

    public function policies()
    {
        return $this->hasMany(MemberPolicy::class, 'member_id', 'member_id');
    }

    public function currentPolicy()
    {
        return $this->hasOneThrough(CorporatePolicy::class, MemberPolicy::class, 'member_id', 'code', 'member_id', 'policy_id')
            ->where('status', 'active')
            ->orderBy('end', 'DESC');
        // return $this->hasOne(MemberPolicy::class, 'member_id', 'member_id')->where('status', 'active')->latestOfMany();
    }

    public function currentActivePolicy()
    {
        return $this->hasOneThrough(CorporatePolicy::class, MemberPolicy::class, 'member_id', 'code', 'member_id', 'policy_id')
            ->where('corporate_policies.start', '<', now())
            ->where('corporate_policies.end', '>', now())
            ->where('member_policies.start', '<', now())
            ->where('member_policies.end', '>', now());
    }

    public function division()
    {
        return $this->hasOneThrough(CorporateDivision::class, CorporateEmployee::class, 'member_id', 'id', 'id', 'division_id');
    }
    /* -------------------------------------------------------------------------- */

    /* -------------------------------------------------------------------------- */
    /*                            Accessors & Mutators                            */
    /* -------------------------------------------------------------------------- */
    protected function age(): Attribute
    {
        return Attribute::make(
            get: fn () => Carbon::parse($this->birth_date)->diffInYears(now())
        );
    }

    protected function fullName(): Attribute
    {
        $arr = [];

        if (!empty($this->person->name_prefix)) {
            $arr[] = $this->person->name_prefix;
        }

        $arr[] = $this->person->name;

        if (!empty($this->person->name_suffix)) {
            $arr[] = $this->person->name_suffix;
        }

        return Attribute::make(
            get: fn () => !$this->person ? null : implode(' ', $arr)
        );
    }

    protected function genderCode(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->gender ? ($this->gender == 'female' ? 'F' : 'M') : $this->gender
        );
    }

    protected function name(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->person->name ?? ($this->name ?? null)
        );
    }

    protected function birthDate(): Attribute
    {
        $date = $this->person->birth_date ?? ($this->birth_date ?? null);

        return Attribute::make(
            get: fn () => !empty($date) ? Carbon::parse($date)->format('Y-m-d') : null
        );
    }

    protected function gender(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->person->gender ?? null
        );
    }
    /* -------------------------------------------------------------------------- */
}
