<?php

namespace App\Models;

use Config\Lookups;

/**
 * Staff logins for the current tenant. `role` is validated against
 * App\Config\Lookups::$staffRoles rather than hard-coded here, so adding a
 * role in a later phase is a config change (see Lookups for why).
 */
class UserModel extends TenantModel
{
    protected $table            = 'users';
    protected $primaryKey       = 'id';
    protected $useAutoIncrement = true;
    protected $returnType       = 'object';
    protected $useTimestamps    = true;

    protected $allowedFields = [
        'full_name',
        'email',
        'phone',
        'photo_path',
        'password_hash',
        'role',
        'is_active',
        'basic_salary',
        'employee_id',
        'ssnit_number',
        'ghana_card_number',
        'bank_name',
        'bank_branch',
        'bank_account_number',
    ];

    public function __construct()
    {
        parent::__construct();

        $roles = array_keys((new Lookups())->staffRoles);

        $this->validationRules = [
            // Only ever checked as a {id} placeholder below (see
            // tenant_unique's own doc comment on the pattern) — CI4
            // requires the placeholder field to carry its own rule entry
            // or it throws a LogicException, even though this field is
            // never itself the thing being validated for real. A caller
            // that wants an update()'s uniqueness checks to correctly
            // exclude its own row must pass 'id' => $id in the data
            // array — see ProfileController::update() for why this
            // matters (saving your own unchanged email/employee_id/
            // ssnit_number/ghana_card_number would otherwise fail as a
            // false "already taken" collision against your own row).
            'id'        => 'permit_empty|integer',
            'full_name' => 'required|max_length[150]',
            'email'     => 'required|valid_email|max_length[150]|tenant_unique[users.email,id,{id}]',
            'phone'     => 'permit_empty|max_length[20]',
            'role'      => 'required|in_list[' . implode(',', $roles) . ']',
            // Payslip identity fields — all optional, but a value that IS
            // entered shouldn't collide with another staff member's (see
            // AddIdentificationFieldsToUsers's migration comment).
            'employee_id'       => 'permit_empty|max_length[30]|tenant_unique[users.employee_id,id,{id}]',
            'ssnit_number'      => 'permit_empty|max_length[30]|tenant_unique[users.ssnit_number,id,{id}]',
            'ghana_card_number' => 'permit_empty|max_length[30]|tenant_unique[users.ghana_card_number,id,{id}]',
            'bank_name'         => 'permit_empty|max_length[100]',
            'bank_branch'       => 'permit_empty|max_length[100]',
            'bank_account_number' => 'permit_empty|max_length[50]',
        ];
    }

    /**
     * Verifies a login attempt. Returns the user row (without the hash) on
     * success, or null on any failure (unknown email, wrong password,
     * deactivated account) — deliberately the same null for all of those
     * so a login form never reveals which part was wrong.
     */
    public function verifyCredentials(string $email, string $password): ?object
    {
        $user = $this->where('email', $email)->where('is_active', 1)->first();

        if ($user === null || ! password_verify($password, $user->password_hash)) {
            return null;
        }

        unset($user->password_hash);

        return $user;
    }

    public function search(string $term)
    {
        return $this->groupStart()
            ->like('full_name', $term)
            ->orLike('email', $term)
            ->groupEnd();
    }

    /**
     * The Staff Users list's search/filters — mirrors GuestModel::
     * filterList() (same "return $this chainable, controller adds
     * ->paginate()" shape).
     *
     * @param array{q?: string, role?: string, status?: string} $filters
     */
    public function filterList(array $filters): static
    {
        $builder = ! empty($filters['q']) ? $this->search($filters['q']) : $this;

        if (! empty($filters['role'])) {
            $builder->where('role', $filters['role']);
        }

        if (($filters['status'] ?? '') === 'active') {
            $builder->where('is_active', 1);
        } elseif (($filters['status'] ?? '') === 'inactive') {
            $builder->where('is_active', 0);
        }

        return $builder->orderBy('full_name', 'asc');
    }
}
