<?php
/**
 * @author      Flycart (Alagesan)
 * @license     http://www.gnu.org/licenses/gpl-3.0.html
 * @link        https://www.flycart.org
 * */

namespace Wlpr\App\Models;
class PointAction extends Base
{
    function __construct()
    {
        parent::__construct();
        $this->table = self::$db->prefix . 'wlpr_user_point_actions';
        $this->primary_key = 'id';
        $this->fields = array(
            'user_email' => '%s',
            'points' => '%s',
            'action' => '%s',
            'order_id' => '%s',
            'product_id' => '%s',
            'admin_user_id' => '%s',
            'log_data' => '%s',
            'created_date' => '%s',
            'is_expire_mail_send' => '%d',
            'expire_mail_date' => '%s',
            'expire_status' => '%s',
            'expire_date' => '%s',
            'remaining_point' => '%s'
        );
    }

    function beforeTableCreation() {}

    function runTableCreation()
    {
        $create_table_query = "CREATE TABLE IF NOT EXISTS {$this->table} (
				 `{$this->getPrimaryKey()}` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
                 `user_email` varchar(180) DEFAULT NULL,
                 `points` BIGINT SIGNED DEFAULT 0,
                 `action` varchar(180) DEFAULT NULL,
                 `order_id` varchar(180) DEFAULT NULL,
                 `product_id` varchar(180) DEFAULT NULL,
                 `admin_user_id` BIGINT UNSIGNED DEFAULT NULL,
                 `log_data` longtext DEFAULT NULL,
                 `is_expire_mail_send` INT(11) DEFAULT 0,
                 `expire_mail_date` datetime DEFAULT NULL,
                 `created_date` datetime DEFAULT NULL,
                 `expire_status` varchar(180) DEFAULT NULL,
                 `expire_date` datetime DEFAULT NULL,
                 `remaining_point` BIGINT UNSIGNED DEFAULT 0,
                PRIMARY KEY (`{$this->getPrimaryKey()}`)
			)";
        $this->createTable($create_table_query);
    }

    function afterTableCreation() {
        global $wpdb;
        if ( self::$db->get_var( "SHOW TABLES LIKE '{$this->table}'" ) ) {
            $existing_columns = $wpdb->get_col("DESC {$this->table}", 0);
            if(!in_array('is_expire_mail_send',$existing_columns)){
                self::$db->query(
                    "ALTER TABLE `{$this->table}` ADD COLUMN is_expire_mail_send INT(11) DEFAULT 0"
                );
            }
            if(!in_array('expire_mail_date',$existing_columns)){
                self::$db->query(
                    "ALTER TABLE `{$this->table}` ADD COLUMN expire_mail_date datetime DEFAULT NULL"
                );
            }

            if(!in_array('expire_status',$existing_columns)){
                self::$db->query(
                    "ALTER TABLE `{$this->table}` ADD COLUMN expire_status varchar(180) DEFAULT 'in-active'"
                );
            }

            if(!in_array('expire_date',$existing_columns)){
                self::$db->query(
                    "ALTER TABLE `{$this->table}` ADD COLUMN expire_date datetime DEFAULT NULL"
                );
            }

            if(!in_array('product_id',$existing_columns)){
                self::$db->query(
                    "ALTER TABLE `{$this->table}` ADD COLUMN product_id varchar(180) DEFAULT NULL"
                );
            }

            if(!in_array('remaining_point',$existing_columns)){
                self::$db->query(
                    "ALTER TABLE `{$this->table}` ADD COLUMN remaining_point BIGINT DEFAULT 0"
                );
            }

            $query = $wpdb->prepare("SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = %s AND COLUMN_NAME = %s",$this->table,'points');
            $existing_column = $wpdb->get_row($query,OBJECT);
            if(isset($existing_column->COLUMN_TYPE) && in_array($existing_column->COLUMN_TYPE,array('bigint unsigned','bigint'))){
                self::$db->query(
                    "UPDATE `{$this->table}` SET expire_mail_date = NULL WHERE CAST(expire_mail_date AS CHAR(20)) = '0000-00-00 00:00:00'"
                );
                self::$db->query(
                    "UPDATE `{$this->table}` SET expire_date = NULL WHERE CAST(expire_date AS CHAR(20)) = '0000-00-00 00:00:00'"
                );
                self::$db->query(
                    "ALTER TABLE `{$this->table}` MODIFY COLUMN points BIGINT SIGNED DEFAULT 0"
                );
            }
        }

        $is_already_migrated = get_option('wlpr_already_migration');
        $point_migration_action = new PointAction();

        $migration_status = true;
        if($is_already_migrated){
            $migration_status = false;
        }
        if($migration_status){
            $migration_record = $point_migration_action->getWhere('points > 0', '*', false);
            if(count($migration_record) <= 0){
                // No record.. so no need migration
                update_option('wlpr_already_migration',1);
                $migration_status = false;
            }
        }

        if($migration_status){
            $where = $wpdb->prepare('points > 0 AND expire_status IN("%s","%s","%s")',array('active','used','expired'));
            $migration_record = $point_migration_action->getWhere($where, '*', false);
            if(!empty($migration_record)){
                update_option('wlpr_already_migration',1);
                $migration_status = false;
            }
        }
    }

    function earn_point_action($user_email, $action = 'order-placed', $args = array())
    {
        global $wpdb;
        if (!empty($user_email) && !empty($action)) {
            $user_email = sanitize_email($user_email);
            $action = (string)$action;
            $insert_data = array(
                'user_email' => $user_email,
                'points' => (isset($args['points']) && !empty($args['points'])) ? $args['points'] : 0,
                'remaining_point' => (isset($args['points']) && !empty($args['points']) && $args['points'] > 0) ? $args['points'] : 0,
                'action' => $action,
                'created_date' => (isset($args['created_date']) && !empty($args['created_date'])) ? $args['created_date'] : date("Y-m-d h:i:s")
            );
            // optional parameter: associated order record
            if (isset($args['order_id']) && $args['order_id']) {
                $insert_data['order_id'] = (string)$args['order_id'];
            }
            if(isset($args['product_id']) && $args['product_id']){
                $insert_data['product_id'] = $args['product_id'];
            }
            if (isset($args['log_data']) && $args['log_data']) {
                $insert_data['log_data'] = json_encode($args['log_data']);
            }
            $point_setting = get_option('wlpr_settings');
            $expired_number = (isset($point_setting['wlpr_expired_after']) && !empty($point_setting['wlpr_expired_after'])) ? $point_setting['wlpr_expired_after'] : 0;
            $expired_period = (isset($point_setting['wlpr_expired_period']) && !empty($point_setting['wlpr_expired_period'])) ? $point_setting['wlpr_expired_period'] : 'DAY';
            $expired_date_after = '';
            if (!empty($expired_number)) {
                $expired_date_after = "+ $expired_number $expired_period";
            }
            if (!empty($expired_date_after) && $insert_data['remaining_point'] > 0) {
                $expired_date_after = date('Y-m-d H:i:s', strtotime($expired_date_after));
                $insert_data['expire_date'] = $expired_date_after;
                $insert_data['expire_status'] = 'active';
            }else{
                $insert_data['expire_status'] = 'in-active';
            }

            $expired_email_date = (isset($point_setting['wlpr_expired_email_after']) && !empty($point_setting['wlpr_expired_email_after'])) ? $point_setting['wlpr_expired_email_after'] : 0;
            $expired_email_period = (isset($point_setting['wlpr_expired_email_period']) && !empty($point_setting['wlpr_expired_email_period'])) ? $point_setting['wlpr_expired_email_period'] : 'DAY';
            $expired_email_date_after = '';
            if (!empty($expired_email_date)) {
                $expired_email_date_after = "+ $expired_email_date $expired_email_period";
            }

            $insert_data['expire_mail_date'] = null;
            if(!empty($expired_email_date_after)){
                $insert_data['expire_mail_date'] = date('Y-m-d H:i:s', strtotime($expired_email_date_after));
            }

            if (is_admin()) {
                $admin_user = wp_get_current_user();
                $insert_data['admin_user_id'] = $admin_user->ID;
            }
            $rev_product_id = (isset($args['product_id']) && $args['product_id']) ? $args['product_id']: 0;
            if (in_array($action,array('account-signup','birth_date','facebook_share','twitter_share','email_share','whatsapp_share'))) {
                $point_action_table = new PointAction();
                $where = $wpdb->prepare("user_email = %s AND action = %s", array($user_email, $action));
                $point_action_data = $point_action_table->getWhere($where, '*', true);
                if (!empty($point_action_data)) {
                    return false;
                }
                if ($this->insertRow($insert_data)) {
                    return true;
                }
            } elseif (in_array($action, array('order-placed')) && isset($insert_data['order_id']) && !empty($insert_data['order_id'])) {
                $point_action_table = new PointAction();
                $where = $wpdb->prepare("user_email = %s AND action = %s AND order_id = %s", array($user_email, $action, $insert_data['order_id']));
                $point_action_data = $point_action_table->getWhere($where, '*', true);
                if (!empty($point_action_data)) {
                    if ($this->updateRow(array(
                        'points' => $insert_data['points'],
                        'remaining_point' => $insert_data['remaining_point'],
                        'created_date' => $insert_data['created_date']
                    ), array(
                        'user_email' => $user_email,
                        'action' => $action,
                        'order_id' => $insert_data['order_id']
                    ))) {
                        return true;
                    }
                } else {
                    if ($this->insertRow($insert_data)) {
                        return true;
                    }
                }
            } elseif (in_array($action,array('order-cancelled','order-refunded','admin-adjustment','import','rest-api'))){
                if ($this->insertRow($insert_data)) {
                    return true;
                }
            }elseif ($action == 'product-review' && $rev_product_id > 0){
                $point_action_table = new PointAction();
                $where = $wpdb->prepare("user_email = %s AND action = %s AND product_id = %s",$user_email, $action, (int)$rev_product_id);
                $point_review_action_data = $point_action_table->getWhere($where, '*', true);
                if(!empty($point_review_action_data)){
                    return false;
                }elseif ($this->insertRow($insert_data)) {
                    return true;
                }

            } elseif (in_array($action, array( 'referral_point', 'referring_user', 'on_birth_date'))) {
                if ($this->insertRow($insert_data)) {
                    return true;
                }
            }
        }
        return false;
    }

    public function redeem_point_action($user_email, $action, $args = array())
    {
        global $wpdb;
        if (!empty($user_email) && !empty($action)) {
            $user_email = sanitize_email($user_email);
            $action = (string)$action;
            if (in_array($action, array('order-cancelled', 'order-redeem', 'order-refunded', 'admin-adjustment', 'rest-api', 'import'))) {
                $point_action_table = new PointAction();
                $where = $wpdb->prepare("user_email = %s AND expire_status IN('%s','%s') AND remaining_point > 0 ORDER BY id ASC", array($user_email,'active','in-active'));
                $point_action_data = $point_action_table->getWhere($where, '*', false);
                $redeem_points = (isset($args['points']) && !empty($args['points'])) ? $args['points'] : 0;
                if ($redeem_points < 0) {
                    $redeem_points = -$redeem_points;
                }
                //redeem data
                $insert_data = array(
                    'user_email' => $user_email,
                    'points' => (int)(isset($args['points'])) ? $args['points'] : 0,
                    'action' => $action,
                    'is_expire_mail_send' => 0,
                    'created_date' => isset($args['created_date']) && $args['created_date'] ? $args['created_date'] : date("Y-m-d h:i:s"),
                    'expire_status' => 'in-active',
                    'expire_date' => null,
                    'remaining_point' => 0
                );
                // optional parameter: associated order record
                if (isset($args['order_id']) && $args['order_id']) {
                    $insert_data['order_id'] = (string)$args['order_id'];
                }
                if(isset($args['product_id']) && $args['product_id']){
                    $insert_data['product_id'] = (int)$args['product_id'];
                }
                // optional parameter: associated arbitrary data
                if (isset($args['log_data']) && $args['log_data']) {
                    $insert_data['log_data'] = json_encode($args['log_data']);
                }
                // automatically associate this log entry with an admin user if in the admin
                if (is_admin() && !defined('DOING_AJAX')) {
                    $admin_user = wp_get_current_user();
                    $insert_data['admin_user_id'] = (int)$admin_user->ID;
                }
                $point_action_table->insertRow($insert_data);
                if (!empty($point_action_data) && $redeem_points) {

                    foreach ($point_action_data as $point_data) {
                        if ($point_data->remaining_point < $redeem_points) {
                            $redeem_points -= $point_data->remaining_point;
                            $this->updateRow(array(
                                'remaining_point' => 0,
                                'expire_status' => 'used'
                            ), array(
                                'id' => (int)$point_data->id
                            ));
                        } else {
                            $remaining_point = $point_data->remaining_point - $redeem_points;
                            $redeem_points = 0;
                            $expire_status = $point_data->expire_status;
                            if($remaining_point <= 0){
                                $expire_status = 'used';
                            }
                            $this->updateRow(array(
                                'remaining_point' => (int)$remaining_point,
                                'expire_status' => $expire_status
                            ), array(
                                'id' => (int)$point_data->id
                            ));
                        }
                        if (empty($redeem_points)) {
                            break;
                        }
                    }
                }
                if (empty($redeem_points)) {
                    return true;
                }
            }
        }
        return false;
    }

    function get_expiring_points($date_expire_before)
    {
        global $wpdb;
        return $wpdb->get_results($wpdb->prepare("SELECT * FROM {$this->table} WHERE expire_date < %s AND expire_status = %s;", (string)$date_expire_before,'active'));
    }

    function get_email_expire_points($email_expire_date,$date_expire_before,$expire_since = ''){
        global $wpdb;
        $expire_since = '';
        if (!$expire_since) {
            $expiring_points = $wpdb->prepare("SELECT * FROM {$this->table} WHERE created_date < %s AND NOT points = 0 AND is_expire_mail_send = 0", (string)$date_expire_before);
        } else {
            $expiring_points = $wpdb->prepare("SELECT * FROM {$this->table} WHERE created_date < %s AND created_date >= %s AND points = 0 AND is_expire_mail_send = 0", (string)$date_expire_before, $expire_since);
        }
        $email_points = $wpdb->get_results($wpdb->prepare("SELECT expire_point.* FROM (".$expiring_points.") as expire_point WHERE expire_point.created_date < %s",(string)$email_expire_date));
        return $email_points;
    }

    function get_expire_email_list(){
        global $wpdb;
        // created date : 01:01:2020
        // mail need to send : 03:01:2020
        // expire date: 04:01:2020
        $current_date = date('Y-m-d H:i:s');
        $expiring_points = $wpdb->prepare("SELECT * FROM {$this->table} WHERE expire_mail_date <= %s AND is_expire_mail_send = 0 AND expire_status = %s", $current_date,'active');
        return $wpdb->get_results($expiring_points);;
    }
}