<?php defined('BASEPATH') OR exit('No direct script access allowed');

class User_model extends CI_Model
{
    private $table       = 'users';
    private $siswa_table = 'siswa';

    public function __construct()
    {
        parent::__construct();
        $this->load->database(); // default = hsidb
    }

    /* ===========================
     * AUTH
     * =========================== */

    /**
     * Login siswa (by Email/Phone + RoleName = 'Siswa')
     *
     * @param string $identity  email atau phone
     * @param string $password
     * @param string $roleName
     * @return object|false
     */
    public function login($identity, $password, $roleName = 'Siswa')
    {
        $user = $this->db->select('u.*, r.RoleName')
            ->from($this->table.' u')
            ->join('roles r', 'r.RoleID = u.RoleID', 'inner')
            ->group_start()
                ->where('u.Email', $identity)
                ->or_where('u.Phone', $identity)
            ->group_end()
            ->where('r.RoleName', $roleName)
            ->get()
            ->row();

        if (!$user) {
            return false;
        }

        return $this->verify_password($user, $password) ? $user : false;
    }

    /**
     * Login admin (RoleID 1/2)
     *
     * @param string $identity
     * @param string $password
     * @return object|false
     */
    public function login_admin($identity, $password)
    {
        $user = $this->db->select('u.*, r.RoleName')
            ->from($this->table.' u')
            ->join('roles r', 'u.RoleID = r.RoleID', 'left')
            ->group_start()
                ->where('u.Email', $identity)
                ->or_where('u.Phone', $identity)
            ->group_end()
            ->where_in('u.RoleID', [1, 2])
            ->get()
            ->row();

        if (!$user) {
            return false;
        }

        return $this->verify_password($user, $password) ? $user : false;
    }

    /**
     * Verifikasi password terhadap record user
     * - Prioritas cek hash
     * - Tetap support kolom Password (plain) untuk data lama
     *
     * @param object $user
     * @param string $password
     * @return bool
     */
    private function verify_password($user, $password)
    {
        $password = (string) $password;

        // Prefer hash
        if (!empty($user->PasswordHash) && password_verify($password, $user->PasswordHash)) {
            return true;
        }

        // Legacy: cek kolom Password plain text (kalau masih ada)
        if (!empty($user->Password) && hash_equals((string)$user->Password, $password)) {
            return true;
        }

        return false;
    }

    /* ===========================
     * CRUD USER
     * =========================== */

    /**
     * Buat user baru
     *
     * @param array $data
     * @return int|false  UserID atau false kalau gagal
     */
    public function create_user(array $data)
    {
        // whitelist kolom users
        $row = [
            'Username'  => $data['Username'] ?? null,
            'Email'     => $data['Email']    ?? null,
            'Phone'     => $data['Phone']    ?? null,
            'RoleID'    => isset($data['RoleID']) ? (int)$data['RoleID'] : 3,
            'CreatedAt' => $data['CreatedAt'] ?? date('Y-m-d H:i:s'),
        ];

        // Password
        if (!empty($data['PasswordPlain'])) {
            $plain               = (string) $data['PasswordPlain'];
            $row['PasswordHash'] = password_hash($plain, PASSWORD_DEFAULT);

            // NOTE: masih simpan plain untuk kompatibilitas kode lama.
            // Kalau nanti semua sudah migrasi ke hash saja, kolom ini bisa di-null-kan.
            $row['Password']     = $plain;

        } elseif (!empty($data['Password'])) {
            $plain               = (string) $data['Password'];
            $row['PasswordHash'] = password_hash($plain, PASSWORD_DEFAULT);
            $row['Password']     = $plain;
        }

        $ok = $this->db->insert($this->table, $row);
        if (!$ok) {
            $err = $this->db->error(); // ['code'], ['message']
            log_message('error', 'User_model::create_user failed: '.$err['code'].' '.$err['message']);
            return false;
        }

        return (int) $this->db->insert_id();
    }

    public function get_user_by_id($user_id)
    {
        return $this->db->get_where($this->table, ['UserID' => (int)$user_id])->row();
    }

    public function get_by_id($user_id)
    {
        return $this->get_user_by_id($user_id);
    }

    public function get_all_users()
    {
        return $this->db->get($this->table)->result();
    }

    /**
     * Update user
     *
     * @param int   $user_id
     * @param array $data
     * @return bool
     */
    public function update_user($user_id, array $data)
    {
        $row = [];

        foreach (['Username','Email','Phone','RoleID','SiswaID','CreatedAt'] as $k) {
            if (array_key_exists($k, $data)) {
                $row[$k] = $data[$k];
            }
        }

        if (!empty($data['PasswordPlain'])) {
            $plain               = (string) $data['PasswordPlain'];
            $row['PasswordHash'] = password_hash($plain, PASSWORD_DEFAULT);
            $row['Password']     = $plain;
        } elseif (!empty($data['Password'])) {
            $plain               = (string) $data['Password'];
            $row['PasswordHash'] = password_hash($plain, PASSWORD_DEFAULT);
            $row['Password']     = $plain;
        }

        if (empty($row)) {
            // tidak ada field yang diupdate
            return true;
        }

        $this->db->where('UserID', (int)$user_id);
        $ok = $this->db->update($this->table, $row);

        if (!$ok) {
            $err = $this->db->error();
            log_message('error', 'User_model::update_user failed: '.$err['code'].' '.$err['message']);
        }

        return $ok;
    }

    public function delete_user($user_id)
    {
        return $this->db->delete($this->table, ['UserID' => (int)$user_id]);
    }

    /* ===========================
     * SISWA RELATED
     * =========================== */

    /**
     * Ambil user + siswa (left join)
     */
    public function get_user_with_siswa($user_id)
    {
        return $this->db
            ->select('u.UserID, u.Username, u.Email, u.Phone, u.CreatedAt,
                      s.SiswaID, s.NamaLengkap, ss.NamaStatus')
            ->from($this->table.' u')
            ->join($this->siswa_table.' s', 'u.UserID = s.UserID', 'left')
            ->join('statussiswa ss', 's.StatusID = ss.StatusID', 'left')
            ->where('u.UserID', (int)$user_id)
            ->get()
            ->row();
    }

    /**
     * Generate SiswaID dengan format: HSI00001, HSI00002, dst
     *
     * @param string $prefix  default 'HSI'
     * @return string
     */
    public function generate_siswa_id(string $prefix = 'HSI'): string
    {
        $prefix = strtoupper($prefix);

        $last = $this->db->select('SiswaID')
            ->from($this->siswa_table)
            ->like('SiswaID', $prefix, 'after')
            ->where('SiswaID IS NOT NULL', null, false)
            ->order_by('SiswaID', 'DESC')
            ->limit(1)
            ->get()
            ->row();

        $seq = 1;
        if ($last && preg_match('/^'.preg_quote($prefix, '/').'(\d+)$/', $last->SiswaID, $m)) {
            $seq = (int) $m[1] + 1;
        }

        // 5 digit: 00001, 00002, ...
        return $prefix . str_pad((string)$seq, 5, '0', STR_PAD_LEFT);
    }

    /**
     * Assign SiswaID ke user & tabel siswa
     *
     * @param int    $user_id
     * @param string $prefix  default 'HSI'
     * @return string|null    SiswaID baru atau null kalau gagal
     */
    public function assign_siswa_id($user_id, string $prefix = 'HSI'): ?string
    {
        $user_id = (int) $user_id;

        // pastikan ada record siswa-nya
        $siswa = $this->db->get_where($this->siswa_table, ['UserID' => $user_id])->row();
        if (!$siswa) {
            log_message('error', 'assign_siswa_id: siswa untuk UserID '.$user_id.' tidak ditemukan');
            return null;
        }

        $new_id = $this->generate_siswa_id($prefix);

        $this->db->where('UserID', $user_id)->update($this->siswa_table, ['SiswaID' => $new_id]);
        // kalau kolom SiswaID di users dipakai, ikut di-update
        if ($this->db->field_exists('SiswaID', $this->table)) {
            $this->db->where('UserID', $user_id)->update($this->table, ['SiswaID' => $new_id]);
        }

        return $new_id;
    }
}
