<?php
/**
 * Copyright (C) 2007,2008  Arie Nugraha (dicarve@yahoo.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

/* MEMBER BASE LIBRARY */
use SLiMS\{Mail,Plugins};

class member
{
    # class properties
    public $member_id = null;
    public $member_name = null;
    public $member_type_id = null;
    public $member_type_name = null;
    public $register_date = null;
    public $expire_date = null;
    public $member_email = null;
    public $inst_name = null;
    public $is_member = false;
    public $member_image = '';
    public $member_notes = null;
    public $library_id = null;
    
    // ========== TAMBAHAN MULTI-LIBRARY: Member Type Relasi ==========
    public $member_types = array(); // Semua relasi member_type
    public $active_member_types = array(); // Hanya yang aktif
    // ========== AKHIR TAMBAHAN ==========
    
    protected $is_expire = true;
    protected $is_pending = true;
    protected $member_type_prop = array();
    protected $obj_db = false;

    # class constructor
    public function __construct($obj_db, $str_member_id)
    {
        // assign simbio database object to property
        $this->obj_db = $obj_db;
        
        // ========== MODIFIKASI: Ambil data member + library_id ==========
        $_member_q = $this->obj_db->query(sprintf("SELECT m.*, mt.*, m.library_id FROM member AS m
            LEFT JOIN mst_member_type AS mt ON m.member_type_id=mt.member_type_id
            WHERE member_id='%s'", $str_member_id));
        // ========== AKHIR MODIFIKASI ==========

        if ($_member_q->num_rows > 0) {
            // set the is_member property flag to TRUE
            $this->is_member = true;
            $_member_d = $_member_q->fetch_assoc();
            // assign database value to class properties
            $this->member_id = $_member_d['member_id'];
            $this->member_name = $_member_d['member_name'];
            $this->member_type_id = $_member_d['member_type_id'];
            $this->member_type_name = $_member_d['member_type_name'];
            $this->register_date = $_member_d['register_date'];
            $this->expire_date = $_member_d['expire_date'];
            $this->member_email = $_member_d['member_email'];
            $this->inst_name = $_member_d['inst_name'];
            $this->member_image = $_member_d['member_image'];
            $this->member_notes = $_member_d['member_notes'];
            $this->is_pending = (bool)$_member_d['is_pending'];
            
            // ========== TAMBAHAN: library_id ==========
            $this->library_id = $_member_d['library_id'];
            // ========== AKHIR TAMBAHAN ==========
            
            $this->member_type_prop = array(
                    'loan_limit' => $_member_d['loan_limit'],
                    'loan_periode' => $_member_d['loan_periode'],
                    'enable_reserve' => $_member_d['enable_reserve'],
                    'reserve_limit' => $_member_d['reserve_limit'],
                    'member_periode' => $_member_d['member_periode'],
                    'reborrow_limit' => $_member_d['reborrow_limit'],
                    'fine_each_day' => $_member_d['fine_each_day'],
                    'grace_periode' => $_member_d['grace_periode']
                );

            // ========== TAMBAHAN: Ambil data relasi member_member_type ==========
            $this->loadMemberTypes();
            // ========== AKHIR TAMBAHAN ==========

            // is membership expired ?
            // compare it with current date
            $_current_date = date('Y-m-d');
            $_expired_date = simbio_date::compareDates($_current_date, $_member_d['expire_date']);
            if ($_expired_date <= $_member_d['expire_date']) {
                $this->is_expire = false;
            }
        }
    }
    
    // ========== TAMBAHAN: Method untuk load member types ==========
    /**
     * Load all member types for this member from member_member_type
     */
    public function loadMemberTypes()
    {
        if (!$this->member_id) return;
        
        $query = "SELECT mmt.*, mt.member_type_name, mt.loan_limit, mt.loan_periode, 
                  mt.fine_each_day, mt.grace_periode, mt.member_periode,
                  l.library_code, l.library_name
                  FROM member_member_type mmt
                  JOIN mst_member_type mt ON mmt.member_type_id = mt.member_type_id
                  LEFT JOIN mst_library l ON mmt.library_id = l.library_id
                  WHERE mmt.member_id = '" . $this->obj_db->escape_string($this->member_id) . "'
                  ORDER BY mmt.library_id ASC";
        
        $result = $this->obj_db->query($query);
        $this->member_types = array();
        $this->active_member_types = array();
        
        while ($row = $result->fetch_assoc()) {
            $this->member_types[] = $row;
            if ($row['is_active'] == 1) {
                $this->active_member_types[$row['library_id']] = $row;
            }
        }
    }
    
    /**
     * Get active member type for a specific library
     * @param int $library_id
     * @return array|null
     */
    public function getActiveMemberType($library_id)
    {
        if (isset($this->active_member_types[$library_id])) {
            return $this->active_member_types[$library_id];
        }
        return null;
    }
    
    /**
     * Get all member types for this member
     * @return array
     */
    public function getAllMemberTypes()
    {
        return $this->member_types;
    }
    
    /**
     * Set active member type for a specific library
     * @param int $member_type_id
     * @param int $library_id
     * @return bool
     */
    public function setActiveMemberType($member_type_id, $library_id)
    {
        // Nonaktifkan semua member_type aktif di library ini
        $this->obj_db->query("UPDATE member_member_type 
            SET is_active = 0 
            WHERE member_id = '" . $this->obj_db->escape_string($this->member_id) . "' 
            AND library_id = " . (int)$library_id);
        
        // Aktifkan member_type yang dipilih
        $check = $this->obj_db->query("SELECT id FROM member_member_type 
            WHERE member_id = '" . $this->obj_db->escape_string($this->member_id) . "' 
            AND member_type_id = " . (int)$member_type_id . " 
            AND library_id = " . (int)$library_id);
        
        if ($check->num_rows > 0) {
            // Update existing
            $this->obj_db->query("UPDATE member_member_type 
                SET is_active = 1 
                WHERE member_id = '" . $this->obj_db->escape_string($this->member_id) . "' 
                AND member_type_id = " . (int)$member_type_id . " 
                AND library_id = " . (int)$library_id);
        } else {
            // Insert new
            $this->obj_db->query("INSERT INTO member_member_type 
                (member_id, member_type_id, library_id, is_active) 
                VALUES ('" . $this->obj_db->escape_string($this->member_id) . "', 
                " . (int)$member_type_id . ", " . (int)$library_id . ", 1)");
        }
        
        // Reload member types
        $this->loadMemberTypes();
        return true;
    }
    
    /**
     * Get loan rules for specific library (including loan_rules override)
     * @param int $library_id
     * @param int $coll_type_id (optional)
     * @param int $gmd_id (optional)
     * @return array
     */
    public function getLoanRules($library_id, $coll_type_id = null, $gmd_id = null)
    {
        $active = $this->getActiveMemberType($library_id);
        if (!$active) {
            return $this->member_type_prop;
        }
        
        $member_type_id = $active['member_type_id'];
        
        // Cari loan_rules yang paling spesifik
        $sql = "SELECT * FROM mst_loan_rules 
                WHERE library_id = " . (int)$library_id . " 
                AND member_type_id = " . (int)$member_type_id;
        
        if ($coll_type_id && $gmd_id) {
            // Cari dengan coll_type + gmd
            $result = $this->obj_db->query($sql . " AND coll_type_id = " . (int)$coll_type_id . " AND gmd_id = " . (int)$gmd_id);
            if ($result->num_rows > 0) return $result->fetch_assoc();
        }
        
        if ($coll_type_id) {
            // Cari dengan coll_type saja
            $result = $this->obj_db->query($sql . " AND coll_type_id = " . (int)$coll_type_id . " AND gmd_id IS NULL");
            if ($result->num_rows > 0) return $result->fetch_assoc();
        }
        
        if ($gmd_id) {
            // Cari dengan gmd saja
            $result = $this->obj_db->query($sql . " AND coll_type_id IS NULL AND gmd_id = " . (int)$gmd_id);
            if ($result->num_rows > 0) return $result->fetch_assoc();
        }
        
        // Cari default (member_type saja)
        $result = $this->obj_db->query($sql . " AND coll_type_id IS NULL AND gmd_id IS NULL");
        if ($result->num_rows > 0) return $result->fetch_assoc();
        
        // Return default dari member_type
        return array(
            'loan_limit' => $active['loan_limit'],
            'loan_periode' => $active['loan_periode'],
            'fine_each_day' => $active['fine_each_day'],
            'grace_periode' => $active['grace_periode']
        );
    }
    // ========== AKHIR TAMBAHAN ==========


    # checking wether member is valid or not
    # return : boolean
    public function valid()
    {
        return $this->is_member;
    }


    # checking wether membership is already expired
    # return : boolean
    public function isExpired()
    {
        return $this->is_expire;
    }


    # checking wether membership is pending
    # return : boolean
    public function isPending()
    {
        return $this->is_pending;
    }


    # get all member properties
    # retuen : array
    public function getMemberTypeProp()
    {
        // return all member information as an array
        return $this->member_type_prop;
    }
    
    // ========== TAMBAHAN: Method getLibraryId ==========
    public function getLibraryId()
    {
        return $this->library_id;
    }
    // ========== AKHIR TAMBAHAN ==========


    # get info about item being lent by member
    # return : array
    protected function getItemLoan($int_loan_rules = 0)
    {
        $_arr_on_loan = array();
        // count how many items is in loan for this member
        if ($int_loan_rules) {
            $_sql_str = "SELECT item_code FROM loan AS l
                WHERE member_id='".$this->member_id."' AND is_lent=1 AND is_return=0 AND loan_rules_id=$int_loan_rules";
        } else {
            $_sql_str = "SELECT item_code FROM loan AS l
                WHERE member_id='".$this->member_id."' AND is_lent=1 AND is_return=0";
        }
        $_count_q = $this->obj_db->query($_sql_str);
        while ($_count_d = $_count_q->fetch_row()) {
            $_arr_on_loan[] = $_count_d[0];
        }

        return $_arr_on_loan;
    }


    # get an array of member's overdue data
    public static function getOverduedLoan($obj_db, $str_member_id)
    {   //

        $_overdues = array();
        $_ovd_title_q = $obj_db->query(sprintf('SELECT l.loan_id, l.item_code, i.price, i.price_currency,
            b.title, l.loan_date,
            l.due_date, (TO_DAYS(DATE(NOW()))-TO_DAYS(due_date)) AS \'Overdue Days\', b.image
            FROM loan AS l
            LEFT JOIN item AS i ON l.item_code=i.item_code
            LEFT JOIN biblio AS b ON i.biblio_id=b.biblio_id
            WHERE (l.is_lent=1 AND l.is_return=0 AND TO_DAYS(due_date) < TO_DAYS(\''.date('Y-m-d').'\')) AND l.member_id=\'%s\'', $str_member_id));
        while ($_ovd_title_d = $_ovd_title_q->fetch_assoc()) {
            $_overdues[] = $_ovd_title_d;
        }

        return $_overdues;
    }

    /**
     * Toggle active status of a member type
     * @param int $rel_id - ID dari member_member_type
     * @return bool
     */
    public function toggleMemberType($rel_id)
    {
        $rel_id = (int)$rel_id;
        // Get current status
        $query = $this->obj_db->query("SELECT is_active, library_id FROM member_member_type WHERE id = $rel_id AND member_id = '" . $this->obj_db->escape_string($this->member_id) . "'");
        if ($query->num_rows == 0) return false;
        
        $data = $query->fetch_assoc();
        $new_status = $data['is_active'] == 1 ? 0 : 1;
        
        // Jika mengaktifkan, nonaktifkan yang lain di library yang sama
        if ($new_status == 1) {
            $this->obj_db->query("UPDATE member_member_type SET is_active = 0 
                WHERE member_id = '" . $this->obj_db->escape_string($this->member_id) . "' 
                AND library_id = " . (int)$data['library_id']);
        }
        
        $this->obj_db->query("UPDATE member_member_type SET is_active = $new_status WHERE id = $rel_id");
        
        // Reload member types
        $this->loadMemberTypes();
        return true;
    }
    
    
    
    # send overdue notice e-mail
    public function sendOverdueNotice()
    {
        // execute registered hook
        Plugins::getInstance()->execute(Plugins::OVERDUE_NOTICE_INIT, ['member' => $this]);

        try {
            // Template
            include SB . 'admin/admin_template/overdueMail.php';
            $overdueTemplate = new overdueMail($this);
            $overdueTemplate->setMinify(true);
            $overdueTemplate->setCirculationData($this->obj_db, self::getOverduedLoan($this->obj_db, $this->member_id));

            // Send email to member
            Mail::to($this->member_email, $this->member_name)
                    ->subject(str_replace(['{member_name}', '{member_email}'], [$this->member_name, $this->member_email], __('Overdue Notice for Member {member_name} ({member_email})')))
                    ->loadTemplate($overdueTemplate)
                    ->send();

            return ['status' => 'SENT', 'message' => __('Overdue notification E-Mail have been sent to ') . $this->member_email];
        } catch (Exception $exception) {
            return ['status' => 'ERROR', 'message' => __('Message could not be sent. Mailer Error: ') . Mail::getInstance()->ErrorInfo];
        }
    }
}