// Site Crons Management Tools
#include "clog.h"
#include "cgi.h"
#include "input.h"
#include "wrenchboard_api.h"
#include "site_crons.h"
#include "email.h"
#include "safestring.h"
#include <string>
#include "pgsql.h"
#include "pgsql_wrapper.h"
#include "cfg.h"
#include <curl/curl.h>
#include "jobs.h"
#include "bko.h"
#include "cron_email.h"
#include "payments.h"

long ReviewReminder(CVars in, CVars &out);
long OfferPending(CVars in, CVars &out);
long InterestPending(CVars in, CVars &out);
long PaymentPending(CVars in, CVars &out);
long DeadlineLineApprachClient(CVars in, CVars &out);
long SignUpPendingReminder(CVars in, CVars &out);
long SignUpStats(CVars in, CVars &out);
long PastDueWarings(CVars in, CVars &out);
long PastDueOffersRefund(CVars in, CVars &out);
long NotificationSystem(CVars in, CVars &out);
long CronTracker(CVars in, CVars &out);
long SendMoneyPending(CVars in, CVars &out);
long ProcessGroupJobs(CVars in, CVars &out);

long ProcessTransferJobs(CVars in, CVars &out);
long ScheduleTransferJobs(CVars in, CVars &out);
long TestNotificationsJobs(CVars in, CVars &out);
long ProcessExpiredOffers(CVars in, CVars &out);
long ScheduleHolidayJobs(CVars in, CVars &out);
long RefreshBlogs(CVars in, CVars &out);
long RefreshPromoActivities(CVars in, CVars &out);
long RegisterPromoPoint(CVars in);
long RegisterPromoAction(CVars in);
long ReferEmailsCleanup();
long ReferEmailsNotification();

/*
CREATE TABLE cron_jobs (
	id SERIAL,
	job_type VARCHAR(50) UNIQUE NOT NULL,
	description VARCHAR(55) NOT NULL,
	added timestamp without time zone DEFAULT now(),
    updated timestamp without time zone DEFAULT now(),
	active INT DEFAULT 0
	);
ALTER TABLE ONLY cron_jobs
    ADD CONSTRAINT cron_jobs_id_key UNIQUE (id);

*/
long sitecrons_calls(CVars in, CVars &out) {
    logfmt(logINFO, "sitecrons_calls()");
    //out["result"] = "YES I GET TO BACK END";
    long call_action = REQ_LONG(in, "call_action", 0, -1);
    CVars x;
    CVars ct,co;
    long ret = 0;
    const char * loc = getenv("REMOTE_ADDR");
    logfmt(logINFO, "sitecrons_calls() action=%lu",call_action);

    switch (call_action) {
        case WRB_CRONJOB_JOBDUE_REMINDER:
            ct["job_type"]="WRB_CRONJOB_JOBDUE_REMINDER"; ct["job_type"].set_valid( true );
            ct["description"]="This is to organize and send job due date remider to client"; ct["description"].set_valid( true );
            CronTracker(ct, co);
            return DeadlineLineApprachClient(in, out);
            break;

        case WRB_CRONJOB_JOBDUE_PAYMENTS:
            ct["job_type"]="WRB_CRONJOB_JOBDUE_PAYMENTS"; ct["job_type"].set_valid( true );
            ct["description"]="This is to organize jonb compleyted remider to owner of task"; ct["description"].set_valid( true );
            CronTracker(ct, co);
            return PaymentPending(in, out);
            break;

        case WRB_CRONJOB_SIGNUP_ALERT:
            ct["job_type"]="WRB_CRONJOB_SIGNUP_ALERT"; ct["job_type"].set_valid( true );
            ct["description"]="General Signup job stats "; ct["description"].set_valid( true );
            CronTracker(ct, co);
            return SignUpStats(in, out);
            break;

        case WRB_CRONJOB_PASTDUE_ALERT:
            ct["job_type"]="WRB_CRONJOB_PASTDUE_ALERT"; ct["job_type"].set_valid( true );
            ct["description"]="This is to organize and send job due date remider to owner of task"; ct["description"].set_valid( true );
            CronTracker(ct, co);
            return PastDueWarings(in, out);
            break;

        case WRB_CRONJOB_OFFER_REFUND_ALERT:
            ct["job_type"]="WRB_CRONJOB_OFFER_REFUND_ALERT"; ct["job_type"].set_valid( true );
            ct["description"]="Offer expired , need to cancel and return deposit for the offer"; ct["description"].set_valid( true );
            CronTracker(ct, co);
            return PastDueOffersRefund(in, out);
            break;

        case WRB_CRONJOB_PENDOFFER_ALERT:
            ct["job_type"]="WRB_CRONJOB_PENDOFFER_ALERT"; ct["job_type"].set_valid( true );
            ct["description"]="Offer is pending remind the client to attend to it before it expires "; ct["description"].set_valid( true );
            CronTracker(ct, co);
            return OfferPending(in, out);
            break;

         case WRB_CRONJOB_NOTIFICATIONS:
             ct["job_type"]="WRB_CRONJOB_NOTIFICATIONS"; ct["job_type"].set_valid( true );
             ct["description"]="Notification System "; ct["description"].set_valid( true );
             CronTracker(ct, co);
             return NotificationSystem(in, out);
            break;

         case WRB_CRONJOB_PENDINGSM:
             ct["job_type"]="WRB_CRONJOB_PENDINGSM"; ct["job_type"].set_valid( true );
             ct["description"]="Alert Pending Transfers "; ct["description"].set_valid( true );
             CronTracker(ct, co);
             return SendMoneyPending(in, out);
            break;

         case WRB_CRONJOB_GROUPJOBS:
                ct["job_type"]="WRB_CRONJOB_GROUPJOBS"; ct["job_type"].set_valid( true );
                ct["description"]="Job Group Processing"; ct["description"].set_valid( true );
                CronTracker(ct, co);
                return ProcessGroupJobs(in, out);
            break;

            case WRB_CRONJOB_TESTNOTIFICATIONS:
                ct["job_type"]="WRB_CRONJOB_TESTNOTIFICATIONS"; ct["job_type"].set_valid( true );
                ct["description"]="Test Notifications Processing"; ct["description"].set_valid( true );
                CronTracker(ct, co);
                return TestNotificationsJobs(in, out);
            break;

            case WRB_CRONJOB_SCHEULETRANSFER:
                ct["job_type"]="WRB_CRONJOB_SCHEULETRANSFER"; ct["job_type"].set_valid( true );
                ct["description"]="Schedule Transfer Processing"; ct["description"].set_valid( true );
                CronTracker(ct, co);
                return ScheduleTransferJobs(in, out);
            break;

            case WRB_CRONJOB_PROCESSTRANSFER:
                ct["job_type"]="WRB_CRONJOB_PROCESSTRANSFER"; ct["job_type"].set_valid( true );
                ct["description"]="Process Transfer Processing"; ct["description"].set_valid( true );
                CronTracker(ct, co);
                return ProcessTransferJobs(in, out);
            break;

            case WRB_CRONJOB_AUTO_OFFEREXPIRE:
                ct["job_type"]="WRB_CRONJOB_AUTO_OFFEREXPIRE"; ct["job_type"].set_valid( true );
                ct["description"]="Process Transfer Expired Offers"; ct["description"].set_valid( true );
                CronTracker(ct, co);
                return ProcessExpiredOffers(in, out);
            break;
//define('WRB_CRONJOB_HOLIDAY_BROADCAST', 786);
            case WRB_CRONJOB_HOLIDAY_BROADCAST:
                ct["job_type"]="WRB_CRONJOB_HOLIDAY_BROADCAST"; ct["job_type"].set_valid( true );
                ct["description"]="Process Transfer Expired Offers"; ct["description"].set_valid( true );
                CronTracker(ct, co);
                return ScheduleHolidayJobs(in, out);
            break;

            case WRB_CRONJOB_APPEMAILS:
                ct["job_type"]="WRB_CRONJOB_APPEMAILS"; ct["job_type"].set_valid( true );
                ct["description"]="Send Email Batch"; ct["description"].set_valid( true );
                CronTracker(ct, co);
                return CronSendMail(in, out);
            break;

            case WRB_CRONJOB_REFRESHBLOG:
                 ct["job_type"]="WRB_CRONJOB_REFRESHBLOG"; ct["job_type"].set_valid( true );
                 ct["description"]="Refresh Blog"; ct["description"].set_valid( true );
                 CronTracker(ct, co);
                 return RefreshBlogs(in, out);
            break;

            case WRB_CRONJOB_PROCESS_VUSA:
                 ct["job_type"]="WRB_CRONJOB_PROCESS_VUSA"; ct["job_type"].set_valid( true );
                 ct["description"]="Process Virtual Card"; ct["WRB_CRONJOB_PROCESS_VUSA"].set_valid( true );
                 CronTracker(ct, co);
                 return AssignVirtualCardWallet(in, out);
            break;

            case WRB_CRONJOB_PROCESS_PROMO:
                  ct["job_type"]="WRB_CRONJOB_PROCESS_PROMO"; ct["job_type"].set_valid( true );
                  ct["description"]="Process Promo Stats"; ct["WRB_CRONJOB_PROCESS_PROMO"].set_valid( true );
                  CronTracker(ct, co);
                  return RefreshPromoActivities(in, out);
            break;

           // define('WRB_CRONJOB_APPEMAILS',       782);
    }

    logfmt(logINFO, "/sitecrons_calls()");
    return ret;
}
long  RefreshPromoActivities(CVars in, CVars &out){
 logfmt(logINFO, "RefreshPromoActivities() ***  **** **** ENTRY");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    try {
        out["total_record"] = "0";
        const PGresult *res, *resF;

        // check if pending
        res = pgsql_query("SELECT * FROM promo_member WHERE status = 1 ORDER BY id DESC LIMIT 120");
        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);

                // check if on pending table
                resF = pgsql_query("SELECT status FROM members_pending where LOWER(username)= LOWER('%s')", rec["email"].c_str());
                if (resF != NULL && pgsql_num_rows(resF) > 0) {
                   pgsql_query("UPDATE promo_member SET updated = now(), status=2 WHERE id = %lu ", rec["id"].Long()); // mo
                    CVars yp;
                    yp["category"] ="SIGNUP"; yp["category"].set_valid( true );
                    yp["admin_id"] = rec["admin_id"]; yp["admin_id"].set_valid( true );
                    yp["description"] = "Sign up was started"; yp["description"].set_valid( true );
                    RegisterPromoAction(yp);
                }
            }
        }

        // check if signup
        res = pgsql_query("SELECT * FROM promo_member WHERE status = 2 ORDER BY id DESC LIMIT 20");
        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);

                // check if on pending table
                resF = pgsql_query("SELECT status FROM members where LOWER(username)= LOWER('%s')", rec["email"].c_str());
                if (resF != NULL && pgsql_num_rows(resF) > 0) {
                   pgsql_query("UPDATE promo_member SET updated = now(), status=3 WHERE id = %lu ", rec["id"].Long()); // mo
                   // now let us register the points
                   CVars xp;
                   xp["category"] ="SIGNUP"; xp["category"].set_valid( true );
                   xp["member_uid"] = rec["uid"];  xp["member_uid"].set_valid( true );
                   xp["admin_id"] = rec["admin_id"]; xp["admin_id"].set_valid( true );
                   xp["points"] = "100";  xp["points"].set_valid( true );
                   RegisterPromoPoint(xp);
                }
            }
        }


        // send reports to admins
        res = pgsql_query("SELECT * FROM promo_admin WHERE status = 1 ORDER BY updated ASC LIMIT 20");
        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);

                //rec["points"] = "0"; rec["points"].set_valid( true );
                rec["today_signup"] = "0"; rec["today_signup"].set_valid( true );
                rec["today_signup_3days"] = "0"; rec["today_signup_3days"].set_valid( true );
                rec["today_signup_7days"] = "0"; rec["today_signup_7days"].set_valid( true );

                promo_email(WRB_CRONJOB_PROCESS_PROMO, rec, out); // send the reminder email
                pgsql_query("UPDATE promo_admin SET updated = now() WHERE id = %lu ", rec["id"].Long()); // mo
            }
        }

        ReferEmailsCleanup(); // clean up account refer
        ReferEmailsNotification();  // end emsil if needed
        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long ScheduleHolidayJobs(CVars in, CVars &out)");
    }
    logfmt(logINFO, "/RefreshPromoActivities()");
    return ret;
   }

long ReferEmailsNotification(){
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;
//in["promo"].c_str(), in["limit"].Long()
    CVars out, in;
    res = pgsql_query(" SELECT p.id AS promo_id, a.firstname AS send_firstname,a.lastname AS send_lastname,"
                      " p.firstname,p.lastname, 'REFPROMO-'||p.uid AS refer_link , p.email "
                      " FROM promo_member p "
                      " LEFT JOIN promo_admin a ON a.id = p.admin_id "
                      " WHERE p.email_sent IS NULL AND p.status = 1 LIMIT 20");
    if (res != NULL && pgsql_num_rows(res) > 0) {
        out["total_record"] = pgsql_num_rows(res);
        for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {

            map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
            if (f.empty()) continue;
            CVars rec;
            map_to_cvars(f, rec);

            promo_email(WRENCHBOARD_PROMOADMIN_ADDLIST, rec, out); // send the reminder email
            pgsql_query("UPDATE promo_member SET email_sent=now() WHERE id =%lu", rec["promo_id"].Long());

        }
    }

    return 0;
}

long ReferEmailsCleanup(){

 logfmt(logINFO, "ReferEmailsCleanup() ***  **** **** ENTRY");

    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;

        // check if pending
        res = pgsql_query("SELECT id, email ,added, status FROM members_refer_friend WHERE status =1 AND added < now() + '-14 days'  LIMIT 20");
        if (res != NULL && pgsql_num_rows(res) > 0) {
            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);
                // check if on pending table

                const PGresult *res1 = pgsql_query("SELECT * FROM members WHERE email='%s'", rec["email"].c_str());
                if (res1 != NULL && pgsql_num_rows(res1) > 0) {
                    pgsql_query("UPDATE members_refer_friend SET status = 5 WHERE status = 1 AND email = '%s' AND id=%lu", rec["email"].c_str(), rec["id"].Long());
                }
                else{
                 pgsql_query("UPDATE members_refer_friend SET status = 0 WHERE status = 1 AND email = '%s' AND id=%lu", rec["email"].c_str(), rec["id"].Long());
                }
            }
        }

return 0;
}

long RegisterPromoPoint(CVars in){
/*
CREATE TABLE promo_points(
		id SERIAL,
		uid uuid DEFAULT  uuid_generate_v4(),
		admin_id INT  REFERENCES promo_admin(id),
		category  VARCHAR(50) NOT NULL,
		point INT DEFAULT 0,
		added timestamp without time zone DEFAULT now()
		);
 ALTER TABLE ONLY promo_points
    ADD CONSTRAINT promo_points_id_key UNIQUE (id);



    ALTER TABLE promo_admin ADD points INT Default 0;

*/

   long ret = PHP_API_BAD_PARAM;
   //const PGresult *res;
    CVars xx;
    try {
        //long blog_id = REQ_LONG(in, "blog_id", 1, -1);
        REQ_STRING (in, "category",   5, 49, "(.*)");
        long admin_id = REQ_LONG(in, "admin_id", 1, -1);
        long points = REQ_LONG(in, "points", 1, -1);

        xx["category"] = in["category"]; xx["category"].set_valid( true );
        xx["point"] = in["points"]; xx["point"].set_valid( true );
        xx["admin_id"] = in["admin_id"]; xx["admin_id"].set_valid( true );
        long point_id = insert_db_record(DBS_VALID, "promo_points", "promo_points_id_seq", xx);
        if( point_id > 0 ){
            pgsql_query("UPDATE promo_admin SET points= points  + %lu WHERE  id = %lu ",  in["points"].Long(),  in["admin_id"].Long());
            CVars yp;
            yp["category"] ="SIGNUP_POINT";
            yp["admin_id"] = in["admin_id"]; yp["admin_id"].set_valid( true );
            yp["description"] = "Sign up was completed";
            RegisterPromoAction(yp);

           ret = PHP_API_OK;
        }

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long RegisterPromoAction(CVars in, CVars &out)");
    }
  return ret;
}

long RegisterPromoAction(CVars in){
   long ret = PHP_API_BAD_PARAM;
    CVars xx;
    try {
        //long blog_id = REQ_LONG(in, "blog_id", 1, -1);
        REQ_STRING (in, "category",   5, 49, "(.*)");
        REQ_STRING (in, "description",   5, 149, "(.*)");
        long admin_id = REQ_LONG(in, "admin_id", 1, -1);

        xx["category"] = in["category"]; xx["category"].set_valid( true );
        xx["description"] = in["description"]; xx["description"].set_valid( true );
        xx["admin_id"] = in["admin_id"]; xx["admin_id"].set_valid( true );
        insert_db_record(DBS_VALID, "promo_actions", "promo_actions_id_seq", xx);

        ret = PHP_API_OK;
        //out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long RegisterPromoAction(CVars in, CVars &out)");
    }
  return ret;
}

long  RefreshBlogs(CVars in, CVars &out){
    long ret = PHP_API_BAD_PARAM;
    CVars xx;
    try {
        long blog_id = REQ_LONG(in, "blog_id", 1, -1);
        REQ_STRING (in, "banner",   5, 149, "(.*)");
        REQ_STRING (in, "title",   5, 149, "(.*)");
        const PGresult *res;
        res = pgsql_query("SELECT * FROM blog_selections WHERE blog_id = %lu", blog_id);

        if (res != NULL && pgsql_num_rows(res) > 0) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
                CVars rec;
                map_to_cvars(f, rec);
                xx["title"] = in["title"]; xx["title"].set_valid( true );
                xx["banner"] = in["banner"]; xx["banner"].set_valid( true );
                update_db_record(DBS_VALID, "blog_selections", xx, rec["id"].Long() );
        }
        else{
                        xx["blog_id"] = in["blog_id"]; xx["blog_id"].set_valid( true );
                        xx["title"] = in["title"]; xx["title"].set_valid( true );
                        xx["banner"] = in["banner"]; xx["banner"].set_valid( true );
                blog_id = insert_db_record(DBS_VALID, "blog_selections", "blog_selections_id_seq", xx);
        }
        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long RefreshBlogs(CVars in, CVars &out)");
    }
    logfmt(logINFO, "/RefreshBlogs()");
    return ret;
}


long  ScheduleHolidayJobs(CVars in, CVars &out){
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    try {
        out["total_record"] = "0";
        const PGresult *res;
        res = pgsql_query("SELECT * FROM holiday_message WHERE  status = 1 AND completed IS NULL ORDER BY id DESC LIMIT 20");

        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);
                cron_email(WRB_CRONJOB_HOLIDAY_BROADCAST, rec, out); // send the cron email
                pgsql_query("UPDATE holiday_message SET status = 5, completed = now() WHERE id = %lu ", rec["id"].Long()); // move the status so no retry
            }
        }
        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long ScheduleHolidayJobs(CVars in, CVars &out)");
    }
    logfmt(logINFO, "/ScheduleHolidayJobs()");
    return ret;
}

long ProcessExpiredOffers(CVars in, CVars &out){
    char vname[30];
     CVars inR;
     CVars outR;
    long ret = PHP_API_BAD_PARAM;
    long refundReturn  = 0;
    try {
        // First stage ; JUST MARK FOR AUTO AND COME BACK
        out["total_record"] = "0";
        const PGresult *res;
        res = pgsql_query("SELECT status,member_id, id AS offer_id, uid,offer_code FROM members_jobs_offer "
                          " WHERE expire <  ( now() - interval '120 minutes' ) "
                          " AND status = 1 "
                          " AND refund_auto IS NULL "
                          " AND payment_id IS NOT NULL "
                          " ORDER BY id ASC LIMIT 10");

        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);
                pgsql_query("UPDATE members_jobs_offer SET  refund_auto= now() "
                " WHERE id = %lu AND  uid::text = '%s' ", rec["offer_id"].Long(),rec["uid"].c_str()); // move the status so no retry
            }
        }

       // STATUS = 2 Now start refund
        res = pgsql_query("SELECT status,member_id, id AS offer_id, uid,offer_code "
                          " FROM members_jobs_offer "
                          " WHERE expire< now() AND status = 1 "
                          " AND refund_auto <  (now() - interval '15 minutes') "
                          " AND refund_status = 2  "
                          " AND payment_id IS NOT NULL "
                          " ORDER BY id ASC LIMIT 10");

        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);
                pgsql_query("UPDATE members_jobs_offer SET  refund_status= 4 "
                " WHERE id = %lu AND  uid::text = '%s' ", rec["offer_id"].Long(),rec["uid"].c_str()); // move the status so no retry

                inR["offer_code"] = rec["offer_code"]; inR["offer_code"].set_valid( true );
                inR["member_id"] = rec["member_id"]; inR["member_id"].set_valid( true );
                inR["offer_result"] = OFFER_EXPIRE; inR["offer_result"].set_valid( true );
                inR["action"] = WRENCHBOARD_JOB_OFFER_CONCLUDE; inR["action"].set_valid( true );
                refundReturn =  WrenchConcludeJobsOffer(inR, outR);

                logfmt(logINFO, "Refund Return **********************  ProcessExpiredOffers(CVars in, CVars &out) = %lu",refundReturn);

                pgsql_query("UPDATE members_jobs_offer SET  refund_status= 5 "
                " WHERE id = %lu AND  uid::text = '%s' ", rec["offer_id"].Long(),rec["uid"].c_str()); // move the status so no retry

            }
        }

//SELECT status,member_id, id, uid,offer_code FROM members_jobs_offer WHERE expire< now() AND status = 1 AND refund_auto <  (now() - interval '15 minutes') AND refund_status =0  AND payment_id IS NOT NULL ORDER BY id ASC LIMIT 10

        res = pgsql_query("SELECT status,member_id, id AS offer_id, uid,offer_code "
                          " FROM members_jobs_offer "
                          " WHERE expire< now() AND status = 1 "
                          " AND refund_auto <  (now() - interval '15 minutes') "
                          " AND refund_status =0  "
                          " AND payment_id IS NOT NULL "
                          " ORDER BY id ASC LIMIT 10");

        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);
                pgsql_query("UPDATE members_jobs_offer SET  refund_status= 2 "
                " WHERE id = %lu AND  uid::text = '%s' ", rec["offer_id"].Long(),rec["uid"].c_str()); // move the status so no retry
            }
        }



        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long ProcessExpiredOffers(CVars in, CVars &out)");
    }




//case WRENCHBOARD_JOB_OFFER_CONCLUDE:
//return WrenchConcludeJobsOffer(in, out);
//break;




    logfmt(logINFO, "/ProcessExpiredOffers()");
    return ret;
}

long ProcessTransferJobs(CVars in, CVars &out){
//         if ( load_db_record(out, "SELECT count(uid) AS pending_count FROM money_transfer  WHERE status =1 AND completed IS NULL ")> 0){
//           if ( out["pending_count"].Long() > 0 ){
//            alert_email(WRB_CRONJOB_PENDINGSM,out, out);
//           }
//         }
return 0;
}

long ScheduleTransferJobs(CVars in, CVars &out){
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    try {
        out["total_record"] = "0";
        const PGresult *res;
        res = pgsql_query("SELECT id, uid, initiatingamount, status, added,proc FROM money_transfer WHERE added > (now() - interval '3000 minutes') AND status = 1 AND completed IS NULL ORDER BY id DESC LIMIT 100");

        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);
                pgsql_query("UPDATE money_transfer SET  proc= 100, updated = now() "
                " WHERE proc = 0 AND  id = %lu AND uid = '%s'", rec["id"].Long(),rec["uid"].c_str()); // move the status so no retry
            }
        }
        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long ScheduleTransferJobs(CVars in, CVars &out)");
    }
    logfmt(logINFO, "/ScheduleTransferJobs()");
    return ret;
}

long TestNotificationsJobs(CVars in, CVars &out){
  long push_ret =  -1;
        CVars xx;
        try{
            xx["member_uid"] = "70d8ecc4-490f-40e5-9cea-0484f0a9f584"; xx["member_uid"].set_valid( true );
            xx["push_text"] = "Notification test system...Olu"; xx["push_text"].set_valid( true );
            push_ret = BkoSendPush( xx, out);

            xx["member_uid"] = "d96607ee-37ac-458f-a57d-7f2027a9ba11"; xx["member_uid"].set_valid( true );
            xx["push_text"] = "Notification test system...Obax"; xx["push_text"].set_valid( true );
            push_ret = BkoSendPush( xx, out);

    //52cee358-759f-42f5-8cfb-d3f77b323c1a
            xx["member_uid"] = "52cee358-759f-42f5-8cfb-d3f77b323c1a"; xx["member_uid"].set_valid( true );
            xx["push_text"] = "Notification test system...Toks"; xx["push_text"].set_valid( true );
            push_ret = BkoSendPush( xx, out);
        } catch (bad_parameter) {
            logfmt(logINFO, "ERROR CALL long TestNotificationsJobs(CVars in, CVars &out)");
        }

return 0;
}

long SendMoneyPending(CVars in, CVars &out){
         if ( load_db_record(out, "SELECT count(uid) AS pending_count FROM money_transfer  WHERE status =1 AND completed IS NULL ")> 0){
           if ( out["pending_count"].Long() > 0 ){
            alert_email(WRB_CRONJOB_PENDINGSM,out, out);
           }
         }
return 0;
}

long ProcessGroupJobs(CVars in, CVars &out){
    long ret = 0;
    long limit = in["limit"].Long();
    logfmt(logINFO, "ENTER ProcessGroupJobs()");
    long push_ret =  -1;
    long status = 0;
    CVars outx;

    const PGresult *res = pgsql_query("SELECT * FROM group_offer_schedule WHERE status = 0 ORDER BY ID ASC LIMIT %lu",limit);
    if (res != NULL && pgsql_num_rows(res) > 0) {
        for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
            if (f.empty()) continue;
            CVars rec;
            map_to_cvars(f, rec);

            pgsql_query("UPDATE group_offer_schedule SET  status= 1 "
                       " WHERE id = %lu AND uid = '%s'", rec["id"].Long(),rec["uid"].c_str()); // move the status so no retry

            if ( load_db_record(outx, "SELECT *  FROM  group_offer_schedule "
                                     " WHERE status  = 1 AND uid = '%s' ORDER BY id DESC LIMIT 1", rec["uid"].c_str())> 0){

            pgsql_query("UPDATE group_offer_schedule SET  status= 2 "
                       " WHERE id = %lu AND uid = '%s'", rec["id"].Long(),rec["uid"].c_str()); // move the status so no retry

            CVars xx;
            xx["bypass"] = "1000";
            xx["member_id"] = outx["member_id"]; xx["member_id"].set_valid( true );
            xx["job_id"]     = outx["job_id"]; xx["job_id"].set_valid( true );
            xx["group_id"]   = outx["group_id"]; xx["group_id"].set_valid( true );
            xx["job_description"] = outx["job_description"]; xx["job_description"].set_valid( true );
            WrenchSendJobsOfferGroup( xx, out);

           pgsql_query("UPDATE group_offer_schedule SET completed=now(), notes='%s', status= 5 "
                     " WHERE id = %lu AND uid='%s'",out["status_msg"].c_str(),  rec["id"].Long(),rec["uid"].c_str() );

          CVars xy;
          xy["member_id"] = xx["member_id"]; xy["member_id"].set_valid( true );
          xy["msg"] = "You have completed processing your offers !!!";
          xy["msg"].set_valid(true);
          plan_notification(xy, out);
            }
        } // for loopp
    } // main nserach

return 0;
}
long NotificationSystem(CVars in, CVars &out){
    long ret = 0;
    //const PGresult *res;
    long limit = in["limit"].Long();
    logfmt(logINFO, "ENTER NotificationSystem()");
    long push_ret =  -1;
    long status = 0;
    const PGresult *res = pgsql_query("SELECT count(member_uid) AS mcount,member_uid "
                                      " FROM  members_notification WHERE status=1 GROUP BY member_uid LIMIT %lu",limit);
    if (res != NULL && pgsql_num_rows(res) > 0) {
        for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
            if (f.empty()) continue;
            CVars rec;
            map_to_cvars(f, rec);

            if ( load_db_record(out, "SELECT id AS notification_id, uid,member_uid,msg FROM  members_notification "
                                     " WHERE status  =1 AND member_uid = '%s' ORDER BY id DESC LIMIT 1", rec["member_uid"].c_str())> 0){

           pgsql_query("UPDATE members_notification SET  status=2 "
                       " WHERE id = %lu", status,out["notification_id"].Long()); // move the status so no retry

            CVars xx;
            xx["member_uid"] = out["member_uid"]; xx["member_uid"].set_valid( true );
            xx["push_text"] = out["msg"]; xx["push_text"].set_valid( true );
            push_ret = BkoSendPush( xx, out);

            if (push_ret == PHP_API_OK){
              xx["send_result"] = "COMPLETED"; xx["send_result"].set_valid( true );
              status = 5;
            }
            else
            {
              xx["send_result"] = "FAIL"; xx["send_result"].set_valid( true );
              status = 7;
            }
              pgsql_query("UPDATE members_notification SET send=now(), send_result='%s', status=%lu "
                          " WHERE id = %lu",xx["send_result"].c_str(), status,out["notification_id"].Long());
            }
        } // for loopp
    } // main nserach

    return ret;
}

long CronTracker(CVars in, CVars &out){
    long ret = 0;
    const PGresult *res;
    try {
        REQ_STRING(in, "job_type", 2, 149, "(.*)");
        REQ_STRING(in, "description", 2, 149, "(.*)");
        
         if ( load_db_record(out, "SELECT id AS cron_id,active FROM cron_jobs WHERE job_type ='%s' ", in["job_type"].c_str())> 0){
           ret = out["active"].Long();
           res = pgsql_query("UPDATE cron_jobs SET updated=now(), active=1 WHERE id = %lu", out["cron_id"].Long());
         }
         else{
            CVars xx;
            xx["job_type"] = in["job_type"];
            xx["job_type"].set_valid(true);
            xx["description"] = in["description"];
            xx["description"].set_valid(true);
            long cron_id = insert_db_record(DBS_VALID, "cron_jobs", "cron_jobs_id_seq", xx);

         }
    }    catch (bad_parameter) {
         out["action_status"] = "Invalid CronTracker Action";
    }
    return ret;
}

long ReviewReminder(CVars in, CVars &out) {



}

long OfferPending(CVars in, CVars &out) {
logfmt(logINFO, "ENTER OfferPending()");
long limit = in["one_limit"].Long();
long mode = REQ_LONG(in, "mode", 0, -1);

  char extraQ[1600];

if ( mode == 100 ){
    snprintf(extraQ, sizeof (extraQ), "  WHERE now() > jo.added +'6 hrs' AND jo.expire > now() AND jo.status = 1 AND jo.public_view =0 AND jo.reminder_count =0 AND jo.reminder_date IS NULL");
}

if ( mode == 200 ){
    snprintf(extraQ, sizeof (extraQ), "  WHERE jo.expire < now() +'12 hrs' AND jo.expire > now() AND jo.status = 1 AND jo.public_view =0 AND jo.reminder_count = 1 AND jo.reminder_date IS NOT NULL");
}

if ( mode == 300 ){
    snprintf(extraQ, sizeof (extraQ), "  WHERE jo.expire < now() +'6 hrs' AND jo.expire > now() AND jo.status = 1 AND jo.public_view =0 AND jo.reminder_count = 2 AND jo.reminder_date IS NOT NULL");
}

const PGresult *res = pgsql_query("SELECT jo.id AS offer_id,jo.added,j.title,jo.expire,"
                                    " to_char(jo.expire, 'Dy Mon dd, yyyy HH:MI AM') AS expire_formated, jo.email, jo.client_id, "
                                    " jo.job_id,jo.reminder_count,jo.reminder_date,jo.email AS firstname, "
                                    " jo.email AS rec_username,j.description AS job_description ,"
                                    " j.timeline_days,j.price, jo.offer_code,cc.description AS currency "
                                    " FROM members_jobs_offer jo "
                                    " LEFT JOIN members_jobs j ON j.id = jo.job_id "
                                    " LEFT JOIN currency cc ON cc.country = j.country "
                                    " %s AND jo.reminder_count < 4  LIMIT %lu ",extraQ, limit);

    if (res != NULL && pgsql_num_rows(res) > 0) {
        for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
            if (f.empty()) continue;
            CVars rec;
            map_to_cvars(f, rec);

            cron_email(WRB_CRONJOB_PENDOFFER_ALERT, rec, out); // send the cron email

            pgsql_exec("UPDATE members_jobs_offer SET reminder_count=reminder_count+1, reminder_date=now()  "\
                       "WHERE id=%lu AND job_id=%lu ", rec["offer_id"].Long(),rec["job_id"].Long());


            CVars xy;
            if ( load_db_record(xy, "SELECT id AS member_id, uid AS member_uid, 'alert.svg' AS icon  "
                                    " FROM members WHERE LOWER(username) = LOWER('%s') ",rec["rec_username"].c_str()) > 0 ){
                         xy["msg"] = "You have received a new offer waiting for you to start!";
                         xy["msg"].set_valid(true);
                         plan_notification(xy, out);
             }

        }
    }
    logfmt(logINFO, "/OfferPending()");
     return 0;
}




long InterestPending(CVars in, CVars &out) {



}

long PastDueOffersRefund(CVars in, CVars &out) {
     logfmt(logINFO, "ENTER PastDueOffersRefund()");
     long contract_id = 0;
    const PGresult *res = pgsql_query("SELECT j.* "
                                    " FROM members_jobs_offer j "
                                    " LEFT JOIN members m1 ON m1.id=j.member_id "
                                    " LEFT JOIN members m2 ON m2.id=j.client_id "
                                    " WHERE j.expire < now() "
                                    " AND j.status = 1 AND j.auto_close IS NULL "
                                    " AND j.payment_id IS NOT NULL LIMIT 1");
    if (res != NULL && pgsql_num_rows(res) > 0) {
        for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
            if (f.empty()) continue;
            CVars rec;
            map_to_cvars(f, rec);
                rec["offer_result"] = OFFER_EXPIRE;
                rec["offer_result"].set_valid( true );

                WrenchConcludeJobsOffer(rec, out);
                pgsql_exec("UPDATE members_jobs_offer SET auto_close=now()  "\
                           "WHERE offer_code='%s'  ", rec["offer_code"].c_str());

        }
    }
    logfmt(logINFO, "/PastDueOffersRefund()");
    return 0;
}

long PastDueWarings(CVars in, CVars &out) {
     logfmt(logINFO, "ENTER PastDueWarings()");
     long contract_id = 0;
    const PGresult *res = pgsql_query("SELECT mc.id AS contract_id, mc.member_id,mc.auto_remind   "
            " FROM members_jobs_contract mc "
            " LEFT JOIN members m ON m.id=mc.client_id "
            " WHERE  mc.status IN (1,2) AND  mc.auto_remind < 3 "
            " AND delivery_date < now() GROUP BY mc.member_id ,mc.auto_remind, contract_id  ORDER BY mc.auto_remind DESC");
    if (res != NULL && pgsql_num_rows(res) > 0) {
        for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
            if (f.empty()) continue;
            CVars rec;
            map_to_cvars(f, rec);
            // note we send once in the loop
            // we need the loop to mar items but wanted to send the email only once
            if ( contract_id != rec["contract_id"].Long() ){
                contract_id = rec["contract_id"].Long();
                cron_email(WRB_CRONJOB_PASTDUE_ALERT, rec, out); // send the cron email
            }
             pgsql_exec("UPDATE members_jobs_contract SET auto_remind=auto_remind + 1,due_remind=now() "\
            				           "WHERE member_id=%lu AND id = %lu  ", rec["member_id"].Long(),rec["contract_id"].Long());

        }
    }
    logfmt(logINFO, "/PastDueWarings()");
    return 0;
}

long SignUpStats(CVars in, CVars &out) {
    logfmt(logINFO, "SignUpStats()");
    try{
            load_db_record(out, "SELECT count(id) AS today_signup FROM members WHERE added::date = now()::date");
            load_db_record(out, "SELECT count(id) AS today_pending_signup FROM members_pending WHERE added::date = now()::date");
            load_db_record(out, "SELECT TO_CHAR(NOW(), 'Day Mon dd, yyyy hh:mm AM') AS report_date");
            load_db_record(out, "SELECT count(*) AS total_task_interest FROM members_offer_interest WHERE added::date = now()::date");
            load_db_record(out, "SELECT count(id) AS total_active_public_jobs FROM members_jobs_offer WHERE status=1 AND public_view= 1 AND expire> now()");
            load_db_record(out, "SELECT count(*) AS total_login FROM members_session WHERE created::date=now()::date");
            load_db_record(out, "SELECT count(id) AS total_private_tasks FROM members_jobs_offer WHERE status=1 AND public_view= 0 AND expire> now()");
            load_db_record(out, "SELECT count(*) AS count_mobile_login FROM mobile_login WHERE updated::date = now()::date");

            load_db_record(out, "SELECT count(id) AS today_signup_3days FROM members WHERE added::date BETWEEN now() +'-3 day(s)' AND now()::date");
            load_db_record(out, "SELECT count(id) AS today_signup_7days FROM members WHERE added::date BETWEEN now() +'-7 day(s)' AND now()::date");
            load_db_record(out, "SELECT count(id) AS today_login_24hrs FROM members WHERE last_login::date BETWEEN now() +'-2 day(s)' AND now()::date");
            //SELECT count(id) AS today_signup_3days FROM members WHERE added::date BETWEEN now() +'-59 day(s)' AND now()::date
            in = out;
            alert_email(WRB_CRONJOB_SIGNUP_ALERT, in, out);
        }    catch (bad_parameter) {
             out["action_status"] = "Invalid SignUpStats Action";
        }
    logfmt(logINFO, "/SignUpStats()");
    return 0;

}

long PaymentPending(CVars in, CVars &out) {
    logfmt(logINFO, "PaymentPending()");
    const PGresult *res = pgsql_query("SELECT count(id) AS preview_count,member_id FROM members_jobs_contract "\
                                         " WHERE status = 4 AND pay_remind IS NULL AND delivery_date < now() +'-1 day(s)'  "\
										 " GROUP BY member_id LIMIT 1");
    if (res != NULL && pgsql_num_rows(res) > 0) {
        for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
            if (f.empty()) continue;
            CVars rec;
            map_to_cvars(f, rec);
            job_email(JOBS_PAYMENT_DUE_MAIL, rec, out); // send the reminder email
            pgsql_exec("UPDATE members_jobs_contract SET pay_remind=now() "\
				           "WHERE member_id=%lu AND status = 4 AND pay_remind IS NULL AND delivery_date < now() +'-1 day(s)' ", rec["member_id"].Long());
        }
    }
    logfmt(logINFO, "/PaymentPending()");
    return 0;

}

long DeadlineLineApprachClient(CVars in, CVars &out) // called
{
    logfmt(logINFO, "DeadlineLineApprachClient()");
	
	// First Reminder 
    const PGresult *res = pgsql_query("SELECT j.client_id,j.id AS contract_id FROM members_jobs_contract j "\
		                                  "WHERE j.due_remind IS NULL AND j.status IN (1,2) "\
										  "AND j.delivery_date > now() AND j.delivery_date < now() + '1 day' "\
										  "AND j.client_id IS NOT NULL AND j.client_id > 0  limit %lu", in["one_limit"].Long());
    if (res != NULL && pgsql_num_rows(res) > 0) {
        for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
            if (f.empty()) continue;
            CVars rec;
            map_to_cvars(f, rec);
            job_email(JOBS_DUE_APPROACH_MAIL, rec, out); // send the reminder email
            pgsql_exec("UPDATE members_jobs_contract SET due_remind=now() WHERE id=%lu", rec["contract_id"].Long());
        }
    }
	
	
	const PGresult *res2 = pgsql_query("SELECT j.client_id,j.id AS contract_id FROM members_jobs_contract j "\
									  "WHERE now() > j.due_remind  + '6 hours'  AND j.status IN (1,2) "\
									  "AND j.delivery_date > now() AND j.delivery_date < now() + '1 day' "\
									  "AND j.client_id IS NOT NULL AND j.client_id > 0  limit %lu", in["one_limit"].Long());
    if (res2 != NULL && pgsql_num_rows(res2) > 0) {
        for (int i = 0, n = pgsql_num_rows(res2); i < n; i++) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res2, i);
            if (f.empty()) continue;
            CVars rec;
            map_to_cvars(f, rec);
            job_email(JOBS_DUE_APPROACH_MAIL, rec, out); // send the reminder email
            pgsql_exec("UPDATE members_jobs_contract SET due_remind=now() WHERE id=%lu", rec["contract_id"].Long());
        }
    }
	
	
    logfmt(logINFO, "/DeadlineLineApprachClient()");
    return 0;
}

long SignUpPendingReminder(CVars in, CVars &out) {



}
