<?php

defined('BASEPATH') or exit('No direct script access allowed');

/**
 * @property CI_Session $session
 * @property Student_parent_model $Student_parent_model
 * @property Parent_model $Parent_model
 */
class MY_Model extends CI_Model
{

    public $database;
    public $database_prefix = "artechsy_praise_crm_app_";
    public $table_prefix = "mas_";
    public $tbl;
    public $gender = ['女', '男'];
    public $paid_mode = [
        'month' => '月費',
        'lesson' => '堂費',
        'period' => '短期非延續性',
    ];
    public $relationship = [
        1 => '父',
        2 => '母',
        3 => '監護人'
    ];
    public $status = [
        0 => '不啟用',
        1 => '啟用',
    ];
    public $tenantname = [
        'main' => '總校',
        'shekmun' => '石門',
        'kids' => 'KIDS'
    ];
    public $fields;
    private $_tenantNo;

    public static $tenant_no;

    public function __construct()
    {
        parent::__construct();
        $this->load->model('System_admin_landing_tenant_model');
        if (empty($this->database))
            $this->_tenantNo = self::$tenant_no  ?? $this->session->has_userdata('tenant_no') ? $this->session->userdata('tenant_no') : '';

        $tenant_no = self::$tenant_no;
        if ($tenant_no && empty($this->database)) $this->database = $tenant_no;

        log_message('debug', self::$tenant_no);
        //        $this->database =$this->System_admin_landing_tenant_model->detail($this->session->userdata('username'))['tenant_no'];
    }

    public function getMode()
    {
        return $this->paid_mode;
    }

    public function getTenantNo()
    {
        return self::$tenant_no ?? $this->_tenantNo;
    }

    public function setTenantNo($tenant_no, $force = true)
    {
        $this->_tenantNo = $tenant_no;
        if (($this->database === "" || $force) && $this->database != 'default') {
            $this->database = $tenant_no;
            self::$tenant_no = $tenant_no;
        }
    }

    public function getFromDB($database, $table, $fields, $start, $length, $orders, $search, $joins)
    {
        if ($database === "") {
            return [];
        }
        $db = $this->load->database($database, TRUE);
        $db->select(implode(', ', $fields));
        $db->from($this->table_prefix . $table);
        foreach ($joins as $joinTbl => $condition) {
            $db->join($this->table_prefix . $joinTbl, $condition);
        }
        if ($database == 'default') {
            $db->where(['tenant_no' => $this->_tenantNo]);
        }
        $db->or_like($search);
        $db->limit($length, $start);
        $db->order_by(implode(', ', $orders));
        return $db->get()->result_array();
    }

    public function addPrefixToFields($fields, $prefix)
    {
        return preg_filter('/^/', $prefix . '.', $fields);
    }

    public function getFromDBFilter($database, $table, $fields, $start, $length, $orders, $search, $joins = [], $keywordfieldname = '')
    {
        if ($database === "") {
            return [];
        }
        $db = $this->load->database($database, TRUE);
        $db->distinct();
        $db->select(implode(', ', $fields));
        $db->from($this->table_prefix . $table);
        if ($database == 'default') {
            list($dummy, $shortname) = explode(" ", $table);
            $db->where([$shortname . '.tenant_no' => $this->_tenantNo]);
        }

        if (count($joins) > 0) {
            foreach ($joins as $joinTbl => $condition) {
                $db->join($joinTbl, $condition);
            }
        }

        if (!empty($search) && !empty($keywordfieldname)) {
            //            log_message('debug','here');
            foreach ($search as $k => $v) {
                if ($v !== '') {
                    if ($k === $keywordfieldname) {
                        $db->like($search);
                    }
                    $db->like($search, 'none');
                }
            }
        }

        $db->order_by(implode(', ', $orders));
        if ($start > -1) {
            $db->limit($length, $start);
        }
        return $db->get()->result_array();
    }

    public function build_datatables($draw, $total, $filtered, $data)
    {
        return [
            'draw' => $draw,
            'recordsTotal' => $total,
            'recordsFiltered' => $filtered,
            'data' => $data,
        ];
    }

    public function insertDB($database, $table, $param, $batch = false, $cu = [])
    {
        if ($database === "") {
            return false;
        }
        $db = $this->load->database($database, TRUE);
        if (!empty($cu)) {
            foreach ($cu as $field => $value) {
                $db->set($field, $value);
            }
        } else {
            $db->set('create_time', 'UNIX_TIMESTAMP()', FALSE);
            $db->set('created_by', $this->session->userdata('userid') ?? 0);
            $db->set('update_time', 'UNIX_TIMESTAMP()', FALSE);
            $db->set('updated_by', $this->session->userdata('userid') ?? 0);
        }
        $batch ? $db->insert_batch($this->table_prefix . $table, $param) : $db->insert($this->table_prefix . $table, $param);

        log_message('debug', $db->last_query());
        return $batch ? [] : $db->insert_id();
    }

    public function insertIndexDB($database, $table, $param)
    {
        if ($database === "") {
            return false;
        }
        $db = $this->load->database($database, TRUE);
        $db->insert($this->table_prefix . $table, $param);
    }

    public function removeIndexDB($database, $table, $where)
    {
        if ($database === "") {
            return false;
        }
        $db = $this->load->database($database, TRUE);
        $db->where($where);
        $db->delete($this->table_prefix . $table);
    }

    public function insertMultiDB($database, $tables, $param1, $param2)
    {
        if ($database === "") {
            return false;
        }
        $db = $this->load->database($database, TRUE);
        $db->trans_start();
        $db->trans_strict('TRUE');
        $db->set('create_time', 'UNIX_TIMESTAMP()', FALSE);
        $db->set('created_by', $this->session->userdata('userid') ?? 0);
        $db->set('update_time', 'UNIX_TIMESTAMP()', FALSE);
        $db->set('updated_by', $this->session->userdata('userid') ?? 0);
        $db->insert($this->table_prefix . $tables[0], $param1);
        $newId = $db->insert_id();
        $db->set('create_time', 'UNIX_TIMESTAMP()', FALSE);
        $db->set('created_by', $this->session->userdata('userid') ?? 0);
        $db->set('update_time', 'UNIX_TIMESTAMP()', FALSE);
        $db->set('updated_by', $this->session->userdata('userid') ?? 0);
        $db->set('product_id', $newId);
        $db->insert($this->table_prefix . $tables[1], $param2);
        $db->trans_complete();

        if ($db->trans_status() === FALSE) {
            $db->trans_rollback();
            return false;
        } else {
            $db->trans_commit();
            return $newId;
        }
    }

    public function getAll($database, $table, $fields = [], $where = null, $tableprefix = true)
    {
        if ($database === "") {
            return [];
        }
        $db = $this->load->database($database, TRUE);
        if (!empty($fields)) {
            $db->select(implode(', ', $fields));
        }
        $tbl = $tableprefix ? $this->table_prefix . $table : $table;
        $db->from($tbl);
        $db->order_by('id ASC');
        if (!is_null($where)) {
            $db->where($where);
        }
        return $db->get()->result_array();
    }

    public function getAllIn($database, $table, $fields = [], $whereField = '', $whereValue = [], $tableprefix = true, $where = [])
    {
        if ($database === "") {
            return [];
        }
        $db = $this->load->database($database, TRUE);
        if (!empty($fields)) {
            $db->select(implode(', ', $fields));
        }
        $tbl = $tableprefix ? $this->table_prefix . $table : $table;
        $db->from($tbl);
        $db->order_by('id ASC');
        //        log_message('debug','empty where?'.empty($where));
        if (!empty($where)) {
            $db->where($where);
        }
        if (!empty($whereValue)) {
            if (empty($whereField)) {
                $whereField = 'id';
            }
            $db->where_in($whereField, $whereValue);
        }
        $data = $db->get()->result_array();
        //                log_message('debug',$db->last_query());
        return $data;
    }

    public function getOne($database, $table, $fields = [], $id = '', $idxname = 'id', $tableprefix = TRUE)
    {
        //                log_message('debug','database:'.$database);//default
        return $this->getOneRow($database, $table, $fields, [$idxname => $id], $tableprefix);
    }

    public function getOneRow($database, $table, $fields = [], $where = [], $tableprefix = TRUE, $order_by = [])
    {
        if ($database === "") {
            return [];
        }
        $db = $this->load->database($database, TRUE);
        /*
		 *  fields:tenant_no
			tbl:student_import_processed;where:27
		 */
        if (!empty($fields)) {
            //            log_message('debug','fields:'.implode(',',$fields));
            $db->select(implode(', ', $fields));
        }
        $tbl = ($tableprefix) ? $this->table_prefix . $table : $table;
        //        log_message('debug','tbl:'.$tbl.';where:'.implode(',',$where));
        $db->from($tbl);
        $db->where($where);
        $row = $db->get()->row_array();
        log_message('debug', 'sql:' . $db->last_query());
        return $row;
    }

    public function saveWhereDB($database, $table, $param, $where, $u = [])
    {
        if ($database === "") {
            return 0;
        }
        $db = $this->load->database($database, TRUE);
        if (!empty($u)) {
            foreach ($u as $field => $value) {
                $db->set($field, $value);
            }
        } else {
            $db->set('update_time', 'UNIX_TIMESTAMP()', FALSE);
            $db->set('updated_by', $this->session->userdata('userid') ?? 0);
        }
        $db->where($where);
        $db->update($this->table_prefix . $table, $param);

        // log_message('debug', $this->db->last_query());
        return $db->affected_rows();
    }

    public function saveDB($database, $table, $param, $id, $idxname = 'id', $u = [])
    {
        if ($database === "") {
            return 0;
        }
        $db = $this->load->database($database, TRUE);
        if (!empty($u)) {
            foreach ($u as $field => $value) {
                $db->set($field, $value);
            }
        } else {
            $db->set('update_time', 'UNIX_TIMESTAMP()', FALSE);
            $db->set('updated_by', $this->session->userdata('userid') ?? 0);
        }
        $db->where($idxname, $id);
        $db->update($this->table_prefix . $table, $param);
        return $db->affected_rows();
    }

    public function deleteDB($database, $table, $id, $multi = false, $idfieldname = 'id')
    {
        if ($database === "") {
            return 0;
        }
        $db = $this->load->database($database, TRUE);
        $multi ? $db->where_in($idfieldname, $id) : $db->where($idfieldname, $id);
        $db->delete($this->table_prefix . $table);
        return $db->affected_rows();
    }

    public function deleteRelatedDB($database, $tables, $idfieldnames, $ids)
    {
        if ($database === "") {
            return false;
        }
        $db = $this->load->database($database, TRUE);
        $db->trans_start();
        $db->trans_strict('TRUE');
        foreach ($idfieldnames as $k => $idfieldname) {
            $db->where_in($idfieldname, $ids);
            $db->delete($this->table_prefix . $tables[$k]);
        }
        $db->trans_complete();

        if ($db->trans_status() === FALSE) {
            $db->trans_rollback();
            return false;
        } else {
            $db->trans_commit();
            return true;
        }
    }

    public function deleteAllDB($database, $table)
    {
        if ($database === "") {
            return false;
        }
        $db = $this->load->database($database, TRUE);
        $db->delete($this->table_prefix . $table);
    }

    public function queryExecute($database, $sql)
    {
        if ($database === "") {
            return false;
        }
        $db = $this->load->database($database, TRUE);
        $db->query($sql);
    }

    protected function throw_exception($msg, $db = null)
    {
        if ($db) $this->db = $db;

        $this->db->trans_rollback();
        throw new Exception($msg);
    }

    public function array_put(&$res, $key, $values)
    {
        if (empty($res[$key])) {
            $res[$key] = [];
        }
        array_push($res[$key], $values);
    }

    public function set_db($db)
    {
        // https://stackoverflow.com/questions/25922968/php-storing-refernece-in-object-property-cannot-assign-by-reference-to-overload
        // $this->db = &$db;
        $this->db->reset_query();

        return $this;
    }

    public function threeYearsInterval()
    {
        $currentYear = date('Y');
        $_currentYear = (int)$currentYear;
        $previousYear = $_currentYear - 1;
        $nextYear = $_currentYear + 1;

        return compact('currentYear', 'previousYear', 'nextYear');
    }

    public function create_batch($params)
    {
        $this->db = $this->load->database($this->database, true);

        $this->db->insert_batch($this->table_prefix . $this->tbl, $params);
    }

    public function get_max_id()
    {
        $this->db = $this->load->database($this->database, TRUE);
        $res = $this->db->from($this->table_prefix . $this->tbl)
            ->select('MAX(id) AS id', null, false)
            ->get()
            ->row_array();
        return $res['id'] ?? 0;
    }

    public function push_notification($data, $model = null, $model_id = null, $student_ids = null, $sent_field = 'sent')
    {
        $tenant_no = $this->getTenantNo();
        $res = $this->session->tempdata('push_notification') ?? [];



        $this->load->model('Student_parent_model');
        $_parentIds = $student_ids != null
            ? $this->Student_parent_model->getAllIn($this->Student_parent_model->database, $this->Student_parent_model->tbl, ['student_id', 'parent_id'], 'student_id', $student_ids, true, ['tenant_no' => $tenant_no])
            : $this->Student_parent_model->getAll($this->Student_parent_model->database, $this->Student_parent_model->tbl, ['student_id', 'parent_id'], ['tenant_no' => $tenant_no]);

        $parentIds = [];
        foreach ($_parentIds as $_parentId) array_push($parentIds, $_parentId['parent_id']);


        $this->load->model('Parent_model');
        $devices = $this->Parent_model->getAllIn($this->Parent_model->database, $this->Parent_model->tbl, ['id', 'fcm_token'], 'id', $parentIds, true, ['tenant_no' => $tenant_no, 'fcm_token IS NOT NULL' => null]);

        if (!empty($devices)) {
            foreach ($devices as $device) {
                array_push($res, [
                    'data' => $data,
                    'token' => $device['fcm_token'],
                    // update sent flag after calling the method push_notification_sent
                    'model' => $model,
                    'model_id' => $model_id,
                    'sent_field' => $sent_field,
                    'tenant_no' => $tenant_no
                ]);
            }
        }

        $this->session->set_tempdata('push_notification', $res);
    }

    public function push_notification_sent($tenant_no, $model_id, $sent_field)
    {
        $this->setTenantNo($tenant_no, true);
        $this->db = $this->load->database($this->database, true);
        return $this->db->update($this->table_prefix . $this->tbl, [$sent_field => 1], ['id' => $model_id]);
    }

    public function listing_map(&$items, $field_name)
    {
        $res = [];
        foreach ($items as $item) {
            if (empty($item[$field_name])) continue;
            $res[$item[$field_name]] = $item;
        }
        $items = $res;
        unset($res);
    }

    public function listing_map_field($items, $field_name)
    {
        $res = [];
        foreach ($items as $item) {
            if (empty($item[$field_name])) continue;
            array_push($res, $item[$field_name]);
        }
        return $res;
    }
}

//''draft','ready','open','completed','deleted','uncollectible','merged','cancelmerged','openaftercancelmerged','void'
abstract class InvoiceStatus
{
    const draft = 'draft';
    const ready = 'ready';
    const open = 'open';
    const completed = 'completed';
    const deleted = 'deleted';
    const uncollectible = 'uncollectible';
    const merged = 'merged';
    const cancelmerged = 'cancelmerged';
    const openaftercancelmerged = 'openaftercancelmerged';
    const void = 'void';
}

//'pending','partial paid','paid'
abstract class PaymentStatus
{
    const pending = 'pending';
    const partialpaid = 'partial paid';
    const paid = 'paid';
}

abstract class Action
{
    const deleted = 'deleted';
    const edited = 'edited';
    const added = 'added';
    const unmerged = 'unmerged';
    const merged = 'merged';
    const linkedorphanreceipts = 'linkedorphanreceipts';
}

abstract class Page
{
    const receipt_approval = 'receipt_approval';
    const invoicing = 'invoicing';
}

abstract class ReceiptApprovalStatus
{
    const pending = 'pending';
    const processed = 'processed';
    const removed = 'removed';
}

abstract class AtmType
{
    const ATM = 'ATM';
    const FPS = 'FPS';
    const Payme = 'Payme';
}

abstract class PaymentType
{
    const Cash = 1;
    const Cheque = 2;
    const CashCheque = 3;
    const Paypal = 4;
    const ATM = 5;
}
