<?php

namespace Mtc\Modules\Members\Models;

use Exception;
use Carbon\Carbon;
use Mtc\Shop\Order;
use Mtc\Shop\Basket;
use App\Src\Encryption;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
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\Support\Arr;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Validator;
use Mtc\Core\Admin\User;
use App\Casts\OptionalEncrypted;
use Mtc\Plugins\Clinic\Src\Logger;
use Mtc\Shop\Assessment\Assessment;
use Mtc\Modules\Members\Classes\Auth;
use Mtc\Plugins\NHS\Classes\NHSMember;
use Mtc\Shop\Events\MemberNoteCreatedEvent;
use Mtc\Modules\Members\Classes\MembersBasket;
use MtcPharmacy\Subscriptions\Classes\Subscription;
use Mtc\Modules\Members\Classes\MemberDuplicateCheck;
use Mtc\Modules\Members\Classes\MemberOauthProviders;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;
/**
 * Eloquent model Member.
 *
 * @author Aleksey Lavrinenko
 * @version 23.08.2016.
 *
 * Database fields:
 * @property int $id
 * @property string $email
 * @property string $contact_no
 * @property string $type
 * @property string $hash
 * @property int $height
 *
 * accessors
 * @property string $fullname
 *
 * @property Carbon $created_at
 * @property Carbon $updated_at
 * @property Collection $addresses
 * @property MembersAddress $addressBilling
 */
class Member extends Model
{
    use MembersBasket;

    use HasFactory;

    protected $table = 'members';

    protected $fillable = [
        'unio_internal_id',
        'is_external',
        'is_activated',
        'email',
        'phone_prefix',
        'contact_no',
        'type',
        'verification_code',
        'verification_code_expiry',
        'prescription_reminder_email',
        'prescription_reminder_sms',
        'dob',
        'gender',
        'height',
        'first_login',
        'referrer_member_id',
    ];

    protected $casts = [
        'prescription_reminder_email' => 'bool',
        'prescription_reminder_sms' => 'bool',
        'email' => OptionalEncrypted::class,
        'contact_no' => OptionalEncrypted::class,
        'conditions' => OptionalEncrypted::class,
        'medications' => OptionalEncrypted::class,
        'allergies' => OptionalEncrypted::class,
        'dob' => OptionalEncrypted::class,
    ];

    public static $searchable = [
        'email',
        'contact_no',
        'dob',
    ];

    private $rules = [
        'confirmed_terms_at' => 'required | date',
        'has_nominated_client_as_pharmacy_of_choice' => 'required',
    ];

    protected static function boot(): void
    {
        parent::boot();

        self::saved(function (self $model) {
            Event::dispatch('Member@saved', $model);
            Encryption::updateHashes($model);
        });
    }

    /**
     * Get DOB in DD.MM.YYYY format
     *
     * @return string
     */
    public function getDob(): string
    {
        if (empty($this->dob)) {
            return '';
        }
        try {
            return Carbon::parse($this->dob)->format('d.m.Y');
        } catch (Exception) {
            return '';
        }
    }


    public function getAge(): int
    {
        try {
            return Carbon::parse($this->dob)->age;
        } catch (Exception $e) {
            return 0;
        }
    }

    private $validation_messages = [];

    public function validate()
    {
        return Validator::make($this->attributes, $this->rules, $this->validation_messages);
    }


    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password'
    ];

    public static $titles = [
        'Mr.',
        'Mrs.',
        'Ms.',
    ];

    public static $genders = [
        'Male',
        'Female',
    ];

    protected $appends = [
        'full_name',
    ];

    /**
     * fullname accessor. Returns Member's full name
     *
     * @return string
     */
    public function getFullnameAttribute()
    {
        $full_name = 'Customer';

        if ($this->addressBilling) {
            $full_name = $this->addressBilling->firstname . ' ' . $this->addressBilling->lastname;
        }

        return $full_name;
    }

    /**
     * password mutator. Hashes the password before setting.
     * @param $password
     */
    public function setPassword($password)
    {
        $this->password = Auth::hashPassword($password);
    }


    // SCOPES

    /**
     * scope withEmail($email). filter members by email
     *
     * @param $query
     * @param $email
     * @return mixed
     */
    public function scopeWithEmail($query, $email)
    {
        return $query->where('email_hash', Encryption::makeHash($email));
    }

    // RELATIONSHIPS

    /**
     * addresses one-to-many relationship.
     *
     * @return HasMany
     */
    public function addresses()
    {
        return $this->hasMany(MembersAddress::class, 'member_id');
    }

    /**
     * addressBilling one-to-one relationship.
     *
     * @return HasOne
     */
    public function addressBilling()
    {
        return $this->hasOne(MembersAddress::class, 'member_id')->billing();
    }

    /**
     * addressShipping one-to-one relationship.
     *
     * @return HasOne
     */
    public function addressShipping()
    {
        return $this->hasOne(MembersAddress::class, 'member_id')->shipping();
    }

    /**
     * Relationship with 3rd party authenticators for this member
     *
     * @return HasMany
     */
    public function authenticators()
    {
        return $this->hasMany(MemberOauthProviders::class, 'member_id');
    }

    public function patientNotes(): HasMany
    {
        return $this->hasMany(MemberNote::class, 'member_id');
    }

    /**
     * Relationship to NHS Member
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function nhs_member()
    {
        return $this->hasOne(NHSMember::class);
    }

    public function assessments()
    {
        return $this->hasMany(Assessment::class);
    }

    public function create_nhs_member()
    {
        $this->refresh();

        if (!$this->nhs_member) {

            if (!$this->addressBilling) {
                throw new Exception("Billing Address is required to create an NHS Member.");
            }

            $nhs_member = new NHSMember();
            $nhs_member->firstname = $this->addressBilling->firstname;
            $nhs_member->lastname = $this->addressBilling->lastname;
            $nhs_member->is_patient = 1;
            $nhs_member->dob = $this->dob;
            $nhs_member->member()->associate($this);
            $nhs_member->save();
        }

        return $this->refresh();
    }


    public function referrer()
    {
        return $this->belongsTo(Member::class, 'referrer_member_id');
    }


    public function referred_members()
    {
        return $this->hasMany(Member::class, 'referrer_member_id');
    }

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

    /**
     * Relationship to Order(s)
     *
     * @return HasMany
     */
    public function orders()
    {
        return $this->hasMany(Order::class, 'member');
    }

    /**
     * Relationship to attributes
     *
     * @return HasMany
     */
    public function attributes(): HasMany
    {
        return $this->hasMany(MemberAttribute::class, 'member_id');
    }

    /**
     * Function to check if current url is within members area
     *
     * @return boolean
     *
     * @author Vladislavs Ignatjevs
     */
    public static function inMembersUrl()
    {
        return (stripos($_SERVER['REQUEST_URI'], "/members") !== false);
    }

    /**
     * Tries to locate duplicate member by combinations of user data
     *
     * @param Member $member
     * @return Model|null|static
     */
    public static function getDuplicate(Member $member)
    {
        // First locate by phone number + address
        $parent_member = (new self())
            ->orderBy('id', 'desc')
            ->join('members_addresses', function ($join) use ($member) {
                $join->on('members_addresses.member_id', '=', 'members.id')
                    ->where('members_addresses.type', 'shipping')
                    ->where('members_addresses.address1', 'LIKE', $member->addressBilling->address1);
            })
            ->where('members.contact_no', '', $member->contact_no)
            ->where('members.id', '<>', $member->id)
            ->first();

        // If not found then try locating by full address + firstname combination
        if (empty($parent_member)) {
            $parent_member = (new self())
                ->orderBy('id', 'desc')
                ->join('members_addresses', function ($join) use ($member) {
                    $join->on('members_addresses.member_id', '=', 'members.id')
                        ->where('members_addresses.type', 'shipping')
                        ->where('members_addresses.address1', 'LIKE', $member->addressBilling->address1)
                        ->where('members_addresses.address2', 'LIKE', $member->addressBilling->address2)
                        ->where('members_addresses.city', 'LIKE', $member->addressBilling->city)
                        ->where('members_addresses.postcode', 'LIKE', $member->addressBilling->postcode)
                        ->where('members_addresses.firstname', 'LIKE', $member->addressBilling->firstname);
                })
                ->where('members.id', '<>', $member->id)
                ->first();
        }
        return $parent_member;
    }

    /**
     * Determines whether a duplicate member exists in the system based on user input
     *
     * @param array $params Array of params, contains arrays info, address
     * @return bool
     */
    public static function memberHasDuplicates(array $params)
    {
        return (App::make(MemberDuplicateCheck::class))->hasDuplicates($params['info']['contact_no'], $params['address'] ?? []);
    }

    /**
     * Get member stats
     *
     * @param $member_id
     * @return array
     */
    public static function getMemberStats($member_id)
    {
        if (empty($member_id)) {
            return [];
        }
        $stats = [
            'average_order_value' => 0,
            'lifetime_value' => 0,
            'number_of_orders' => 0,
            'last_login' => '-',
        ];
        $stats['number_of_orders'] = $order_count = Order::query()->where('member', $member_id)->where('paid', '1')->count();
        if ($order_count > 0) {
            $stats['lifetime_value'] = Order::query()->where('member', $member_id)->sum('cost_total');
            $stats['average_order_value'] = number_format($stats['lifetime_value'] / $order_count, 2, '.', '');
        }
        $last_login = (new Member())->find($member_id)->last_login;
        if ($last_login !== '0000-00-00 00:00:00') {
            $stats['last_login'] = date_convert_db_to_dmy($last_login);
            $stats['last_login'] = convert_date($last_login, 'd/m/Y H:i:s');
        }
        return $stats;
    }

    /**
     * @param $basket_id
     */
    public function setBasketDetails($basket_id)
    {
        /** @var Basket $basket */
        $basket = Basket::query()
            ->with(['billingAddress', 'shippingAddress', 'info'])
            ->find($basket_id);

        $basket->member = $this->id;
        $basket->save();

        $data = [
            'type' => 'billing',
            'firstname' => $this->addressBilling->firstname,
            'lastname' => $this->addressBilling->lastname,
            'address1' => $this->addressBilling->address1,
            'address2' => $this->addressBilling->address2,
            'city' => $this->addressBilling->city,
            'postcode' => $this->addressBilling->postcode,
            'country' => $this->addressBilling->country,
            'state' => $this->addressBilling->state,
            'title' => $this->addressBilling->title,
            'gender' => $this->gender,
        ];

        if ($basket->billingAddress == null) {
            $basket->billingAddress()->create($data);
        } elseif (empty($basket->billingAddress->address1)) {
            $basket->billingAddress->fill($data);
            $basket->billingAddress->save();
        }

        $info = [
            'email' => $this->email,
            'contact_no' => $this->contact_no,
            'phone_prefix' => $this->phone_prefix,
            'dob' => $this->dob ?? '',
        ];

        if ($basket->info == null) {
            $basket->info()->create($info);
        } else {
            $basket->info->fill($info);
            $basket->info->save();
        }

        // Reset session and reload basket as data has now been changed
        $new_basket = new \Basket();
        $new_basket->resetSession();
        $new_basket->Go_Basket();

    }

    public function setAllergies(array $items)
    {
        $this->allergies = json_encode($items);
    }

    public function setConditions(array $items)
    {
        $this->conditions = json_encode($items);
    }

    public function setMedications(array $items)
    {
        $this->medications = json_encode($items);
    }



    public function getAllergiesString($glue = ', ')
    {
        return implode($glue, $this->getAllergiesArray());
    }

    public function getConditionsString($glue = ', ')
    {
        return implode($glue, $this->getConditionsArray());
    }

    public function getMedicationsString($glue = ', ')
    {
        return implode($glue, $this->getMedicationsArray());
    }



    public function getAllergiesArray()
    {
        return (array) json_decode($this->allergies, true);
    }

    public function getConditionsArray()
    {
        return (array) json_decode($this->conditions, true);
    }

    public function getMedicationsArray()
    {
        return (array) json_decode($this->medications, true);
    }


    private function prepare_data_from_input(array &$data)
    {
        if (!trim($data['email'])) {
            $data['email'] = null;
        }

        if (!trim($data['contact_no'])) {
            $data['contact_no'] = null;
        }
    }


    public function update_from_input(array $data)
    {
        // Table 'members'.

        $this->prepare_data_from_input($data);
        $this->fill($data)->save();


        // Table 'members_addresses'.

        $addresses = (array) Arr::get($data, 'addresses');
        foreach ($addresses as $address) {
            switch ($address['type']) {
                case 'shipping':
                    if ($this->addressShipping) {
                        $this->addressShipping->fill($address)->save();
                    } else {
                        $this->addressShipping()->create($address);
                    }
                    break;

                case 'billing':
                    if ($this->addressBilling) {
                        $this->addressBilling->fill($address)->save();
                    } else {
                        $this->addressBilling()->create($address);
                    }
                    break;
            }
        }


        // Table 'nhs_members'.

        $this->create_nhs_member();
        if ($nhs_member_data = Arr::get($data, 'nhs_member')) {
            $this->nhs_member->fill($nhs_member_data);
            $this->nhs_member->save();
        }

        if ($doctor_surgery_data = Arr::get($data, 'doctor_surgery')) {
            if ($this->nhs_member->doctor_surgery) {
                $this->nhs_member->doctor_surgery->fill($doctor_surgery_data)->save();
            } else {
                $this->nhs_member->doctor_surgery()->create($doctor_surgery_data);
            }
        }

    }


    public function can_manage_own_account()
    {
        $can_manage_own_account = false;

        if (!$this->referrer_member_id) {
            $can_manage_own_account = true;
        }

        return $can_manage_own_account;
    }


    public function is_allowed_to_log_in_as_member(Member $member)
    {
        $is_allowed = false;

        if ($this->id) {

            if ($member->referrer_member_id == $this->id) {
                $is_allowed = true;
            }

            if (
                $this->referrer_member_id == $member->id &&
                $_SESSION['IS_ALLOWED_TO_LOG_IN_AS_REFERRER']
            ) {
                $is_allowed = true;
            }

        }

        return $is_allowed;
    }


    public function try_to_log_in()
    {
        $currently_logged_in_member = Auth::getLoggedInMember();

        if (!$currently_logged_in_member->is_allowed_to_log_in_as_member($this)) {
            abort(403, 'You have no permissions to do this.');
            exit;
        }

        Auth::login($this);
        if ($this->can_manage_own_account()) {
            unset($_SESSION['IS_ALLOWED_TO_LOG_IN_AS_REFERRER']);
        } else {
            $_SESSION['IS_ALLOWED_TO_LOG_IN_AS_REFERRER'] = true;
        }
    }


    public function is_email_system_generated()
    {
        $is_system_generated = false;

        if (preg_match("/^patient@.+\.mtc$/", $this->email)) {
            $is_system_generated = true;
        }

        return $is_system_generated;
    }


    public function deactivate()
    {
        $this->is_activated = false;
        $this->save();
    }


    public function getAdminLink()
    {
        return SITE_URL . "/modules/Members/admin/manage_member.php?id={$this->id}";
    }

    /**
     * After logging in / registering, link the completed assessments with the member
     *
     * @return void
     */
    public function linkAssessmentsFromSession(): void
    {
        $assessmentIds = [];
        if (!empty($_SESSION['assessments'])) {
            $assessmentIds = $_SESSION['assessments'];
        }
        if (!empty($_SESSION['category_assessments'])) {
            $categoryAssessmentIds = array_values($_SESSION['category_assessments']);
            $assessmentIds = array_merge($categoryAssessmentIds, $assessmentIds);
        }
        if (empty($assessmentIds)) {
            return;
        }
        Assessment::query()
            ->whereIn('id', $assessmentIds)
            ->where('member_id', 0)
            ->update([
                'member_id' => $this->id,
            ]);
    }

    /**
     * Gets DOB options for FE
     *
     * @return array[]
     */
    public static function getDobOptions(): array
    {
        $date_days = [];

        for ($x = 1; $x < 32; $x++) {

            $day = $x;

            if ($x < 10) {
                $day = '0' . $x;
            }

            $date_days[] = [
                'text' => $day,
                'value' => $x
            ];
        }

        $date_months = [];

        for ($x = 1; $x < 13; $x++) {

            $month = $x;

            if ($x < 10) {
                $month = '0' . $x;
            }

            $date_months[] = [
                'text' => $month,
                'value' => $x
            ];
        }

        $date_years = [];
        $this_year = (int) Date("Y");
        $min_order_age = 16;

        for ($x = ($this_year - $min_order_age); $x >= 1910; $x--) {

            $year = $x;

            if ($x < 10) {
                $year = '0' . $x;
            }

            $date_years[] = [
                'text' => $year,
                'value' => $x
            ];
        }
        return [
            'days' => $date_days,
            'months' => $date_months,
            'years' => $date_years
        ];
    }

    /**
     * Logs patient notes
     *
     * @param array $params
     * @return void
     */
    public function logPatientNotes(array $params): void
    {
        $adminUser = User::getAdminUser();

        $isFlag = !empty($params['isFlag']);

        /** @var MemberNote $memberNote */
        $memberNote = MemberNote::query()
            ->create([
                'member_id' => $this->id,
                'order_id' => $params['orderID'] ?? null,
                'admin_user_id' => $adminUser->id,
                'content' => $params['note'],
                'is_flag' => $isFlag,
                'flag_due' => $params['flagDue'] ?? null,
                'status' => $params['status'] ?? null,
            ]);

        (new Logger($memberNote, $adminUser, $this->id))
            ->log($isFlag ? Logger::MEMBER_FLAG : Logger::MEMBER_NOTE, Logger::ACTION_CREATED, [
                'content' => $params['note'],
            ]);

        Event::dispatch(MemberNoteCreatedEvent::class, new MemberNoteCreatedEvent($memberNote));
    }

    /**
     * Search members
     *
     * @param string $searchQuery
     * @return array
     */

    public static function searchMembers(string $searchQuery): array
    {

        $q = trim($searchQuery);
        if ($q === '') return [];

        // 1) ID shortcut
        if (ctype_digit($q)) {
            $m = self::query()
                ->with(['addressBilling','addressShipping'])
                ->find((int)$q);
            if (!$m) return [];
            self::projectRootPresentationFields($m);
            return [$m->toArray()];
        }

        // Normalisers
        $lower   = static fn (?string $s) => \Illuminate\Support\Str::lower(trim((string) $s));
        $digits  = static fn (?string $s) => preg_replace('/\D+/', '', (string) $s) ?? '';
        $isEmail = static fn (string $s) => str_contains($s, '@') && str_contains($s, '.');

        // 2) Fast exact: EMAIL via email_hash
        if ($isEmail($q)) {
            $hash = \App\Src\Encryption::makeHash($q);
            $rows = self::query()
                ->with(['addressBilling' => fn($qq) => $qq->select('id','member_id','firstname','lastname')])
                ->select('id','email','contact_no','dob')
                //->where('email_hash', $hash)
                ->orWhere('email', $hash)
                ->orderByDesc('id')
                ->limit(20)
                ->get();

            foreach ($rows as $m) self::projectRootPresentationFields($m);
            return $rows->toArray();
        }

        // 3) Fast exact: PHONE via contact_no_hash (accept raw or digits-only user input)
        $phoneDigits = $digits($q);
        if ($phoneDigits !== '' && strlen($phoneDigits) >= 5) {
            $hash = \App\Src\Encryption::makeHash($phoneDigits);
            $rows = self::query()
                ->with(['addressBilling' => fn($qq) => $qq->select('id','member_id','firstname','lastname')])
                ->select('id','email','contact_no','dob')
                ->where('contact_no_hash', $hash)
                ->orderByDesc('id')
                ->limit(20)
                ->get();

            foreach ($rows as $m) self::projectRootPresentationFields($m);
            return $rows->toArray();
        }

        // 4) Fast exact: DOB via dob_hash when query looks like dd/mm/YYYY
        if (preg_match('~^\d{2}/\d{2}/\d{4}$~', $q)) {
            try {
                $dob = \Carbon\Carbon::createFromFormat('d/m/Y', $q)->format('Y-m-d');
                $hash = \App\Src\Encryption::makeHash($dob);
                $rows = self::query()
                    ->with(['addressBilling' => fn($qq) => $qq->select('id','member_id','firstname','lastname')])
                    ->select('id','email','contact_no','dob')
                    ->where('dob_hash', $hash)
                    ->orderByDesc('id')
                    ->limit(20)
                    ->get();

                foreach ($rows as $m) self::projectRootPresentationFields($m);
                return $rows->toArray();
            } catch (\Exception) { /* fall through */ }
        }

        // 5) Fast exact: NAME via members_addresses (billing) firstname/lastname hashes
        //    - one token => match either firstname or lastname exactly
        //    - two tokens => match (first, last) in either order
        $parts = array_values(array_filter(preg_split('/\s+/u', $q) ?: [], fn($t) => $t !== ''));
        if (!empty($parts)) {
            $h = static fn(string $s) => \App\Src\Encryption::makeHash($s);

            $qBase = self::query()
                ->select('members.id','members.email','members.contact_no','members.dob')
                ->leftJoin('members_addresses as ab', function($j) {
                    $j->on('ab.member_id','=','members.id')->where('ab.type','=','billing');
                });

            if (count($parts) === 1) {
                $nameHash = $h($parts[0]);
                $qBase->where(function($w) use ($nameHash) {
                    $w->where('ab.firstname_hash', $nameHash)
                        ->orWhere('ab.lastname_hash',  $nameHash);
                });
            } else {
                // 2+ tokens: try first+last using first two tokens
                [$t1, $t2] = [$parts[0], $parts[1]];
                $h1 = $h($t1);
                $h2 = $h($t2);
                $qBase->where(function($w) use ($h1,$h2) {
                    $w->where(function($w1) use ($h1,$h2) {
                        $w1->where('ab.firstname_hash', $h1)->where('ab.lastname_hash', $h2);
                    })->orWhere(function($w2) use ($h1,$h2) {
                        $w2->where('ab.firstname_hash', $h2)->where('ab.lastname_hash', $h1);
                    });
                });
            }

            $rows = $qBase
                ->with(['addressBilling' => fn($qq) => $qq->select('id','member_id','firstname','lastname')])
                ->orderByDesc('members.id')
                ->limit(20)
                ->get();

            foreach ($rows as $m) self::projectRootPresentationFields($m);
            if ($rows->isNotEmpty()) return $rows->toArray();
        }

        // 6) Nothing matched exactly — return empty (since you asked for full/exact, not partial)
        return [];
    }



    /**
     * Put billing-then-shipping presentation fields on the root so Twig can use:
     *   member.firstname / member.lastname / member.address1 / address2 / city / postcode
     */
    protected static function projectRootPresentationFields(Member $m): void
    {
        $bill = $m->addressBilling;
        $ship = $m->addressShipping;

        $first   = ($bill && $bill->firstname !== '') ? $bill->firstname : ($ship->firstname ?? null);
        $last    = ($bill && $bill->lastname  !== '') ? $bill->lastname  : ($ship->lastname  ?? null);
        $addr1   = ($bill && $bill->address1  !== '') ? $bill->address1  : ($ship->address1  ?? null);
        $addr2   = ($bill && $bill->address2  !== '') ? $bill->address2  : ($ship->address2  ?? null);
        $city    = ($bill && $bill->city      !== '') ? $bill->city      : ($ship->city      ?? null);
        $post    = ($bill && $bill->postcode  !== '') ? $bill->postcode  : ($ship->postcode  ?? null);

        $m->setAttribute('firstname', $first);
        $m->setAttribute('lastname',  $last);
        $m->setAttribute('address1',  $addr1);
        $m->setAttribute('address2',  $addr2);
        $m->setAttribute('city',      $city);
        $m->setAttribute('postcode',  $post);
    }
    /**
     * Whether member's password is empty
     *
     * @return bool
     */
    public function emptyPassword(): bool
    {
        if (empty($this->id)) {
            return true;
        }
        $this->makeVisible(['password']);
        $emptyPassword = empty($this->password);
        $this->makeHidden(['password']);
        return $emptyPassword;
    }

    /**
     * Whether the member requires account verification
     *
     * @return bool
     */
    public function requiresAccountVerification(): bool
    {
        if (empty($this->id)) {
            return false;
        }
        if (!empty($_SESSION['adminId'])) {
            return false;
        }
        return empty($this->account_verified);
    }

    public static function newFactory()
    {
        return \Database\Factories\MemberFactory::new();
    }
}
