<?php 
/**
 * @package    Proxim
 * @author     Davison Pro <davisonpro.coder@gmail.com | https://davisonpro.dev>
 * @copyright  2019 Proxim
 * @version    1.0.0
 * @since      File available since Release 1.0.0
 */

namespace Proxim\Api;

use Db;
use Proxim\Database\DbQuery;
use Proxim\Route;
use Proxim\Coupon;
use Proxim\Site\Site;
use Proxim\Order\Order;
use Proxim\User\Customer;
use Proxim\User\Wallet as CustomerWallet;
use Proxim\User\Employee;
use Proxim\Configuration;
use Proxim\Currency;
use Proxim\Validate;
use Proxim\Tools;
use Proxim\Util\ArrayUtils;
use Proxim\Util\DateUtils;
use Proxim\Crypto\Hashing;
use Proxim\Hook;
use Proxim\Module\Module;
use Proxim\Presenter\Profile\ProfilePresenter;

class Profile extends Route {

    public function register() {
        $app = $this->app;
		$request = $app->request();
		$payload = $request->post();
        $user = $app->container->user;

        $email = ArrayUtils::get($payload, 'email');
        $fname = ArrayUtils::get($payload, 'fname');
        $phone = ArrayUtils::get($payload, 'phone');
        $mobilePhoneCountryHidden = ArrayUtils::get($payload, 'mobilePhoneCountryHidden');
        $password = ArrayUtils::get($payload, 'password');
        $confirmPassword = ArrayUtils::get($payload, 'confirmPassword');

        $agreePrivacyPolicy = ArrayUtils::get($payload, 'agreePrivacyPolicy');
        $agreeSubscription = ArrayUtils::get($payload, 'agreeSubscription');
        $agreeTermsAndConditions = ArrayUtils::get($payload, 'agreeTermsAndConditions');

        /** Email Validation */
        if ( !$email ) {
            return $app->response([
                'success' => false,
                'errors' => [
                    'email' => 'Email is required'
                ]
            ]);
        }

        if(!validate::isEmail($email)) {
            return $app->response([
                'success' => false,
                'errors' => [
                    'email' => 'Enter a valid Email address'
                ]
            ]);
        }

        $customer = $user->getByEmail($email);
        if ( Validate::isLoadedObject($customer) ) {
            return $app->response([
                'success' => false,
                'errors' => [
                    'email' => 'E-mail already registered.'
                ]
            ]);
		}
		
		/** Name Validation */
		if(Configuration::get('AUTH_REQUIRE_NAME', PROX_SITE_ID, true) && !Validate::isName($fname)) {
			return $app->response([
				'success' => false,
				'errors' => [
					'fname' => 'Enter a valid name'
				]
			]);
		}

		/** Phone Validation */
		if(Configuration::get('AUTH_REQUIRE_PHONE', PROX_SITE_ID, true) && !$phone) {
			return $app->response([
				'success' => false,
				'errors' => [
					'fname' => 'Enter a valid phone number'
				]
			]);
		}
         
        /** Password Validation */
		if ( !$password || !Validate::isPasswd($password)) {
            return $app->response([
                'success' => false,
                'errors' => [
                    'password' => 'Password is required'
                ]
            ]);
        }
        
        if ( !$confirmPassword || !Validate::isPasswd($confirmPassword)) {
            return $app->response([
                'success' => false,
                'errors' => [
                    'confirmPassword' => 'Confirm Password is required'
                ]
            ]);
		}

		if ( $confirmPassword !== $password ) {
            return $app->response([
                'success' => false,
                'errors' => [
                    'confirmPassword' => 'Your passwords do not match'
                ]
            ]);
        }
        
        /** Privacy and Terms */
        if( !$agreeTermsAndConditions ) {
            return $app->response([
                'success' => false,
                'errors' => [
                    'agreeTermsAndConditions' => 'You must agree to the Terms and Conditions before registering'
                ]
            ]);
		}

		if( !$agreePrivacyPolicy ) {
            return $app->response([
                'success' => false,
                'errors' => [
                    'agreePrivacyPolicy' => 'You must agree to the Privacy Policy before registering'
                ]
            ]);
		}
        
        $crypto = new Hashing();

        $customer = new Customer();
		$customer->google_analytics_id = Tools::randomGen(32);
		$customer->email = $email;
		$customer->name = $fname ? $fname : ''; 
		$customer->phone = $phone ? $phone : '';
		$customer->country_id = (int) $mobilePhoneCountryHidden;
		$customer->password = $crypto->hash(
            $password,
            PROX_COOKIE_KEY
		);
		$customer->is_subscribed = (bool) $agreeSubscription;
		$customer->policy_accepted = 1;
		$customer->policy_accepted_at =  DateUtils::now();
        $customer->reg_date = DateUtils::now();
        
        if ( $app->container->cookie->referrer_id ) {
			$referrer = new Customer( (int) $app->container->cookie->referrer_id );
			if (Validate::isLoadedObject($referrer)) {
				$customer->referrer_id = $referrer->id;
			}
        }
        
        $ok = $customer->add(true, true);
		if ( !$ok ) {
			return $app->response([
                "success" => false,
                "errors" => [
                    "Sorry, there was a problem creating your account"
                ]
			]);	
        }
		
		Hook::exec('actionCustomerAccountAdd', ['newCustomer' => $customer]);

        $site = new Site( (int) $customer->site_id );
        if( Validate::isLoadedObject($site) ) {
        	$site->customers = $site->customers+1;
        	$site->update();
        }

        // update user 
		$app->updateUser( $customer );

		return $app->response([
			"success" => true,
			"user_id" => $customer->id
		]);	
    }

    public function validateEmail() {
        $app = $this->app;
		$request = $app->request();
		$payload = $request->post();
		$user = $app->container->user;

		$email = ArrayUtils::get($payload, 'email');
		if ( !$email || !Validate::isEmail($email) ) {
			return $app->response([
				"success" => false,
				"errors" => [
					'email' => 'Email is required'
				]
			]);
		}

		$customer = $user->getByEmail($email);
		if (  Validate::isLoadedObject($customer) ) {
			return $app->response([
				"success" => true,
				"data" => [
					"existing_client" => true,
					"user_id" => $customer->id
				]
			]);
		}

		return $app->response([
			"success" => true,
			"data" => [
				"existing_client" => false,
			]
		]);
    }

    public function isSurveyComplete() {
		$app = $this->app;
		$request = $app->request();
		$payload = $request->get();
		$user = $app->container->user;

		return $app->response([
			"success" => true,
			"isSurveyComplete" => false
		]);
    }
    
    public function getProfile() {
		global $globals;
		$app = $this->app;
		$payload = $app->request->get();
		$user = $app->container->user;

		$countries = ArrayUtils::get($globals, 'countries');
		$country_id = array_search($user->country_id, array_column($countries, 'code'));
		$country_code = ArrayUtils::get(array_keys($countries), $country_id);
		$country = ArrayUtils::has($countries, $country_code) ? ArrayUtils::get($countries, $country_code) : array();

		$profilePresenter = new ProfilePresenter();
		$profile = $profilePresenter->present($user);

		return $app->response([
			"success" => true,
			"profile" => $profile
		]);
    }
    
    public function getDiscounts() {
		$app = $this->app;
        $user = $app->container->user;
        $coupons = $customer_coupons = array();

        /** Lifetime discounts **/
        $discount_percent = 0;
        if ( $user->total_spent >= 500 ) {
			if ( $user->total_spent >= 2000 ) {
				$discount_percent = 15;
			} elseif ( $user->total_spent >= 1000 ) {
				$discount_percent = 10;
			} else {
				$discount_percent = 5;
			}

			$coupons[] = array(
				"coupon_id" => (int) $user->id,
				"coupon_type" => (int) Coupon::PERCENT,
				"coupon_code" => $discount_percent."% OFF",
				"value" => (int) $discount_percent,
				"order_id" => null,
				"lifetime" => true,
				"expired_at" => null,
			);
		}

        /** Available active coupons */
		$active_coupons = Coupon::getCoupons( true, true );
		foreach ($active_coupons as $coupon) {
			$coupon_type = ArrayUtils::get($coupon, 'coupon_type');
			$user_id = ArrayUtils::get($coupon, 'user_id');
			if ( $user_id && $user_id != $user->id ) {
				continue;
			}

			$order_id = ArrayUtils::get($coupon, 'order_id');
			if ( $order_id ) {
				$order = new Order( (int) $order_id );
				if (!Validate::isLoadedObject($order)) continue;
				if ($order->customer_id != $user->id) continue;
			}

			if( $coupon_type == Coupon::FREE_UNIT ) {
				$customer_coupons[] = array(
					"id" => (int) $coupon['coupon_id'],
					"service_type_id" =>  (int) $coupon['service_type_id'],
					"type_id" => (int) $coupon['coupon_type'],
					"order_id" => (int) $coupon['order_id'],
				);
			} else {
				$coupons[] = array(
					"coupon_id" => (int) $coupon['coupon_id'],
					"coupon_type" => (int) $coupon['coupon_type'],
					"coupon_code" => $coupon['coupon_code'],
					"value" => (int) $coupon['coupon_value'],
					"order_id" => (int) $coupon['order_id'],
					"lifetime" => false,
					"expired_at" => DateUtils::hasPassed( $coupon['expiry'] ) ? $coupon['expiry'] : null,
				);
			}
		}

		return $app->response([
			"success" => true,
			"user_coupons" => [
				"user_id" => $user->id,
				"totalSpent" => (float) $user->total_spent,
				"discountPercent" => (int) $discount_percent,
				"coupons" => $coupons,
				"customerCoupons" => $customer_coupons
			]
		]);
	}
	
	public function couponExists( $couponCode ) {
		$app = $this->app;
		$user = $app->container->user;

		if(!$couponCode) {
			return $app->response([
				"success" => false,
				"errors" => null
			]);
		}

		$coupon_id = Coupon::getIdByCouponCode( pSql($couponCode) );
		if(!$coupon_id) {
			return $app->response([
				"success" => false,
				"errors" => [
					"This coupon code is invalid or has expired"
				]
			]);
		}

		$coupon = new Coupon( (int) $coupon_id );
		if(!Validate::isLoadedObject($coupon)) {
			return $app->response([
				"success" => false,
				"errors" => [
					"This coupon code is invalid or has expired"
				]
			]);
		}	

		if ( $coupon->site_id != Configuration::get('SITE_ID', $user->site_id) ) {
			return $app->response([
				"success" => false,
				"errors" => [
					"This coupon code is invalid or has expired"
				]
			]);
		}

		// check expiry
		if( !$coupon->active && DateUtils::hasPassed( $coupon->expiry ) ) {
			return $app->response([
				"success" => false,
				"errors" => [
					"This coupon code is invalid or has expired"
				]
			]);
		}

		// validate user ID
		if ( $coupon->user_id && $coupon->user_id != $user->id ) {
			return $app->response([
				"success" => false,
				"errors" => [
					"This coupon code is invalid or has expired"
				]
			]);
		}

		// validate order ID
		if ( $coupon->order_id ) {
			$order = new Order( (int) $coupon->order_id );
			if ( !Validate::isLoadedObject($order) ) {
				return $app->response([
					"success" => false,
					"errors" => [
						"This coupon code is invalid or has expired"
					]
				]);
			}

			if ($order->customer_id != $user->id) {
				return $app->response([
					"success" => false,
					"errors" => [
						"This coupon code is invalid or has expired"
					]
				]);
			}
		}
		

		return $app->response([
			"success" => true,
			"coupon" =>  array(
				"coupon_id" => (int) $coupon->id,
				"coupon_type" => (int) $coupon->coupon_type,
				"coupon_code" => $coupon->coupon_code,
				"value" => (float) $coupon->coupon_value,
				"order_id" => (int) $coupon->order_id,
				"lifetime" => false,
				"expired_at" => DateUtils::hasPassed( $coupon->expiry ) ? $coupon->expiry : null,
			)
		]);
	}
    
    public function getWriters() {
		$app = $this->app;
		$request = $app->request();
		$payload = $request->get();
		$user = $app->container->user;

		$sql = new DbQuery();
        $sql->select('DISTINCT o.writer_id');
        $sql->from('order', 'o');
		$sql->where('o.`customer_id` = '. (int) $user->id);
		$sql->where('o.`status_id` = '. Order::FINISHED );
		$result = Db::getInstance()->executeS($sql);

		$writers = array();
		foreach ( $result as $writer ) {
			$writer = new Employee( (int) $writer['writer_id'] );
			if (Validate::isLoadedObject($writer)) {
				$sql = new DbQuery();
				$sql->select('o.order_id');
				$sql->from('order', 'o');
				$sql->where('o.`customer_id` = '. (int) $user->id);
				$sql->where('o.`writer_id` = '. (int) $writer->id);
				$sql->where('o.`status_id` = '. Order::FINISHED );
				$orderId = Db::getInstance()->getValue($sql);
 
				$writers[] = array(
					"id" => (int) $writer->id,
					"content" =>  "$writer->first_name - $writer->id (completed your order $orderId)",
					"category" => (int) $writer->writer_category,
					"percent" => (int) $writer->writer_percent,
					"value" => (int) $writer->writer_percent
				);
			}
		}

		return $app->response([
			"success" => true,
			"writers" => $writers
		]);
    }
    
    public function updateContacts() {
		$app = $this->app;
		$payload = $app->request->post();
		$user = $app->container->user;

		$name = ArrayUtils::get($payload, 'name');
		if ( !$name || !Validate::isName($name)) {
			return $app->response([
				"success" => false,
				"errors" => [
					"Your name contains invalid characters"
				]
			]);
		} 

		if ( Tools::strlen($name) > 20 ) {
			return $app->response([
				"success" => false,
				"errors" => [
					"Your name must be less than 20 characters long. Please try another"
				]
			]);
		}

		if ( Tools::strlen($name) < 3 ) {
			return $app->response([
				"success" => false,
				"errors" => [
					"Your name must be at least 3 characters long. Please try another"
				]
			]);
		}

		$phone = (int) ArrayUtils::get($payload, 'phone');

        $user->name = $name;
		$user->phone = $phone;
		$ok = $user->update();

		return $app->response([
			"success" => true,
			"errors" => null
		]);	
	}

	public function updatePassword() {
		$app = $this->app;
		$payload =  $app->request->post();
		$user = $app->container->user;

		$oldPassword = ArrayUtils::get($payload, 'oldPassword');
		$newPassword = ArrayUtils::get($payload, 'newPassword');
		$confirmPassword = ArrayUtils::get($payload, 'confirmPassword');

		if (!$oldPassword && !$newPassword) {
			return $app->response([
				"success" => false,
				"errors" => [
					"You must fill in all of the fields"
				]
			]);
		}

		/* validate new password */
		if($newPassword != $confirmPassword) {
			return $app->response([
				"success" => false,
				"errors" => [
					"Your passwords do not match"
				]
			]);
		}

		if( !Validate::isPasswd($newPassword) ) {
			return $app->response([
				"success" => false,
				"errors" => [
					"Password must be at least 6 characters long. Please try another"
				]
			]);
		}

		$crypto = new Hashing();
		$customer = $user->getByEmail(
			$user->email, 
			$oldPassword
		);

		if (!Validate::isLoadedObject($customer)) {
			return $app->response([
				"success" => false,
				"errors" => [
					"Invalid current password"
				]
			]);
		}

		$user->password = $crypto->hash(
            $newPassword,
            PROX_COOKIE_KEY
		);
		$user->update();

		return $app->response([
			"success" => true,
			"errors" => null
		]);
	}

	public function subscribe() {
		$app = $this->app;
		$payload = $app->request->post();
		$user = $app->container->user;

		$isSubscribed = (bool) ArrayUtils::get($payload, 'isSubscribed');

		$user->policy_accepted = 1;
		$user->policy_accepted_at = DateUtils::now();
        $user->is_subscribed = $isSubscribed;
		$ok = $user->update();

        return $app->response([
			"success" => true,
		]);	
    }
    
    public function pushNotificationsEnabled() {
		$app = $this->app;
		$payload = $app->request->post();
		$user = $app->container->user;

		return $app->response([
			"success" => true,
		]);	
	}

	public function policyConfirmation() {
		$app = $this->app;
		$request = $app->request();
		$payload = $request->post();
		$user = $app->container->user;

		$user->policy_accepted = 1;
		$user->policy_accepted_at = DateUtils::now();
		$user->update();

		return $app->response([
			"success" => true,
		]);	
	}
	
	public function getWallet() {
		$app = $this->app;
		$payload = $app->request->post();
		$user = $app->container->user;

		if(!Configuration::get('WALLET_ENABLED', PROX_ADMIN_SITE_ID)) {
			return $app->response([
				"success" => true,
				"wallet" => array(
					"wallet_balance" => (float) toFixed(0),
					"wallet_transactions" => array()
				)
			]);
		}

		$walletId = CustomerWallet::getIdByCustomerId( $user->id );
		$wallet = new CustomerWallet( (int) $walletId );
		if(!Validate::isLoadedObject($wallet)) {
			return $app->response([
				"success" => true,
				"wallet" => array(
					"wallet_balance" => (float) toFixed(0),
					"wallet_transactions" => array()
				)
			]);
		}

		$sql = new DbQuery();
		$sql->from('wallet_transaction');
		$sql->where('wallet_id = ' . (int) $wallet->id );
		$sql->orderBy('wallet_transaction_id DESC');
		$sql->limit(10);
		$result = Db::getInstance()->executeS($sql);

		$transactions = array();
		foreach($result as $transaction) {
			$transactions[] = array(
				'id' => (int) $transaction['wallet_transaction_id'],
				'source' => (string) $transaction['source'],
				'amount' => (float) $transaction['amount'],
				'date' => DateUtils::convertToISOFormat($transaction['date_add'])
			);
		}

		return $app->response([
			"success" => true,
			"wallet" => array(
				"wallet_balance" => (float) $wallet->wallet_balance,
				"wallet_transactions" => $transactions
			)
		]);
		
	}

	public function loadWallet() {
		$app = $this->app;
		$payload = $app->request->post();
		$user = $app->container->user;

		$amount = ArrayUtils::get($payload, 'amount');
		$paymentMethod = ArrayUtils::get($payload, 'paymentMethod');

		if(!Validate::isPrice($amount)) {
			return $app->response([
				"success" => false,
				"errors" => [
					"Enter a valid amount"
				]
			]);
		}

		$paymentModule = Module::getInstanceByName($paymentMethod);
		if(!Validate::isLoadedObject($paymentModule)) {
			return $app->response([
				"success" => false,
				"errors" => "Select a valid payment method"
			]);
		}

		$redirect = Configuration::get('SITE_DOMAIN') . '/checkout/' . $paymentMethod . '/wallet/' . $amount;

		return $app->response([
			"success" => true,
			"redirect_to" => $redirect
		]);
	}


}