<?php
/**
 * @copyright    OCTemplates
 * @support      https://octemplates.net/
 * @license      LICENSE.txt
 */

class ControllerOctemplatesModuleOctStockNotifier extends Controller {

	private $error = array();

    public function index() {
        if ($this->isValidRequest()) {
            $this->language->load('octemplates/module/oct_stock_notifier');

            if (isset($this->request->post['product_id'])) {
				$product_id = (int) $this->request->post['product_id'];
			} else {
				$product_id = 0;
			}

			$this->load->model('catalog/product');

			$product_info = $this->model_catalog_product->getProduct($product_id);

            if ($product_info) {
				$data['oct_stock_notifier_data'] = $oct_stock_notifier_data = $this->config->get('oct_stock_notifier_data');

                $this->load->model('tool/image');

				if ($product_info['image']) {
					$data['thumb'] = $this->model_tool_image->resize($product_info['image'], 150, 150);
				} else {
					$data['thumb'] = '';
				}

				if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) {
					$data['price'] = $this->currency->format($this->tax->calculate($product_info['price'], $product_info['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']);
				} else {
					$data['price'] = false;
				}

				if ((float) $product_info['special']) {
					$data['special'] = $this->currency->format($this->tax->calculate($product_info['special'], $product_info['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']);
				} else {
					$data['special'] = false;
				}

				$data['heading_title_product'] = $product_info['name'];
				$data['href']                  = $this->url->link('product/product', 'product_id=' . $product_id, true);
				$data['product_id']            = (int) $product_id;
				$data['model']                 = $product_info['model'];
				$data['name']      			   = $this->customer->isLogged() ? $this->customer->getFirstName() . " " . $this->customer->getLastName() : '';
				
				$phone = $this->customer->isLogged() ? $this->customer->getTelephone() : '';
				if ($phone) {
					$phone = preg_replace('/[^0-9+]/', '', $phone);
				}
				$data['phone'] = $phone;
				
				$data['email']     			   = $this->customer->isLogged() ? $this->customer->getEmail() : '';

				$oct_promo_data = $this->config->get('theme_oct_promo_data');
				$phone_masks = [];
				$allowed_countries = [];

				if (isset($oct_promo_data['phone_countries']) && is_array($oct_promo_data['phone_countries'])) {
					foreach ($oct_promo_data['phone_countries'] as $country) {
						if (!empty($country['country_code']) && !empty($country['mask'])) {
							$country_code_lower = strtolower($country['country_code']);
							$phone_masks[$country_code_lower] = [
								'mask' => $country['mask'],
								'regex' => !empty($country['regex']) ? $country['regex'] : ''
							];
							$allowed_countries[] = $country_code_lower;
						}
					}
				}
				$data['phone_masks'] = json_encode($phone_masks);
				$data['allowed_countries'] = json_encode($allowed_countries);

				$data['default_phone_country'] = !empty($oct_promo_data['default_phone_country'])
					? strtolower($oct_promo_data['default_phone_country'])
					: 'ua';

				if ($this->config->get('config_account_id')) {
		            $this->load->model('catalog/information');

		            $information_info = $this->model_catalog_information->getInformation($this->config->get('config_account_id'));

		            if ($information_info) {
		                $data['text_terms'] = sprintf($this->language->get('text_oct_terms'), $this->url->link('information/information', 'information_id=' . $this->config->get('config_account_id'), true), $information_info['title'], $information_info['title']);
		            } else {
		                $data['text_terms'] = '';
		            }
		        } else {
		            $data['text_terms'] = '';
		        }

		        $this->response->setOutput($this->load->view('octemplates/module/oct_stock_notifier', $data));
			} else {
				$this->redirectToNotFound();
			} 
        } else {
            $this->redirectToNotFound();
        }
    }

	public function add() {
		if ($this->isValidRequest()) {
			$this->processSubscription();
		} else {
			$this->redirectToNotFound();
		}
	}

	public function cron() {
		$config_data = $this->config->get('oct_stock_notifier_data');

		if (!$this->config->get('oct_stock_notifier_status') || empty($config_data['cron_secret'])) {
			$this->redirectToNotFound();
			return;
		}

		$this->load->model('octemplates/module/oct_abandoned_cart');
		$ip = isset($this->request->server['REMOTE_ADDR']) ? (string)$this->request->server['REMOTE_ADDR'] : 'unknown';

		if ($this->model_octemplates_module_oct_abandoned_cart->isRateLimited($ip, 'cron_stock_notifier', 5, 300)) {
			$this->redirectToNotFound();
			return;
		}

		$secret_key = $config_data['cron_secret'];
		$request_key = isset($this->request->get['cron_secret']) ? (string)$this->request->get['cron_secret'] : '';

		if (!$request_key || $request_key !== $secret_key) {
			if (!$this->model_octemplates_module_oct_abandoned_cart->checkRateLimit($ip, 'cron_stock_notifier', 5, 300)) {
				$this->log->write('[SECURITY] Multiple failed Cron key attempts (Stock Notifier) from IP: ' . $ip);
			}

			$this->redirectToNotFound();
			return;
		}

		$this->processSubscribers();
	}
	
	private function isValidRequest() {
		return $this->config->get('oct_stock_notifier_status') &&
			isset($this->request->server['HTTP_X_REQUESTED_WITH']) &&
			strtolower($this->request->server['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
	}
	
	private function processSubscription() {
		$this->language->load('octemplates/module/oct_stock_notifier');
		$this->load->model('catalog/product');
	
		$json = [];
		$data['oct_stock_notifier_data'] = $this->config->get('oct_stock_notifier_data');
		$product_info = $this->model_catalog_product->getProduct((int) $this->request->post['pid']);
	
		if ($this->validate() && $product_info) {
			$this->load->model('octemplates/module/oct_stock_notifier');
			$data = $this->collectSubscriptionData();
	
			if (!$this->model_octemplates_module_oct_stock_notifier->isAlreadySubscribed($data)) {
				$this->model_octemplates_module_oct_stock_notifier->addRequest($data);
				$this->notifyAdmin($data);
				$json['output'] = $this->language->get('text_success_send');
			} else {
				$json['error']['subscribed'] = $this->language->get('error_already_subscribed');
			}
		} else {
			$json['error'] = $this->error;
		}
	
		$this->respondJson($json);
	}
	
	private function collectSubscriptionData() {
		return [
			'name' => $this->request->post['name'] ?? null,
			'phone' => $this->request->post['phone'] ?? null,
			'email' => $this->request->post['email'] ?? null,
			'pid' => (int) $this->request->post['pid'],
			'customer_id' => $this->customer->isLogged() ? $this->customer->getId() : 0
		];
	}
	
	private function respondJson($json) {
		$this->response->addHeader('Content-Type: application/json');
		$this->response->setOutput(json_encode($json));
	}
	
	private function processSubscribers() {
		$this->load->model('octemplates/module/oct_stock_notifier');
		$this->load->model('catalog/product');
		$this->language->load('octemplates/module/oct_stock_notifier');
		
		$waitingProducts = $this->model_octemplates_module_oct_stock_notifier->getWaitingProducts();
	
		foreach ($waitingProducts as $product) {
			$product_info = $this->model_catalog_product->getProduct((int)$product['product_id']);
			
			if (!$product_info) {
				continue;
			}
			
			$product['name'] = $product_info['name'];
			$subscribers = $this->model_octemplates_module_oct_stock_notifier->getCustomersByProductId((int) $product['product_id']);
			$this->notifySubscribers($subscribers, $product);
		}
	}
	
	private function notifySubscribers($subscribers, $product) {
		foreach ($subscribers as $subscriber) {
			if (!empty($subscriber['email'])) {
				$mailData = $this->prepareMailData($subscriber, $product);
				$this->sendMail($subscriber['email'], $mailData);
				$this->model_octemplates_module_oct_stock_notifier->updateSubscriptionStatus((int)$subscriber['subscription_id']);
			}

			if (!empty($subscriber['phone'])) {
				$oct_sms_settings = $this->config->get('oct_sms_settings');

				if (empty($oct_sms_settings['oct_sms_token'])) {
					continue;
				}

				$template_code = 'oct_stock_notifier';
				$language_id = (int)$subscriber['language_id'];

				if (isset($oct_sms_settings['templates'][$template_code]['status']) && $oct_sms_settings['templates'][$template_code]['status']) {
					if (isset($oct_sms_settings['templates'][$template_code]['message'][$language_id]) && !empty($oct_sms_settings['templates'][$template_code]['message'][$language_id]) && isset($oct_sms_settings['templates'][$template_code]['edit_localization'])) {
						$sms_template = $oct_sms_settings['templates'][$template_code]['message'][$language_id];
					} else {
						$sms_template = $this->language->get('default_sms_template');
					}

				if (!empty($sms_template)) {
						$customer_name = strip_tags($subscriber['customer_name'] ?? '');
						$customer_name = mb_substr($customer_name, 0, 50);

						$product_name = isset($product['name']) && !empty($product['name']) ? strip_tags($product['name']) : 'Product';
						$product_name = mb_substr($product_name, 0, 100);

						$product_link = $this->url->link('product/product', 'product_id=' . (int)$product['product_id']);

						$replace = array(
							'[customer_name]' => $customer_name,
							'[product_name]' => $product_name,
							'[product_link]' => $product_link,
							'[store]' => $this->config->get('config_name')
						);						
					
						$sms_message = str_replace(array_keys($replace), array_values($replace), $sms_template);

						$this->load->model('octemplates/module/oct_sms_notify');
						$this->model_octemplates_module_oct_sms_notify->sendNotification(array(
							'phone' => $subscriber['phone'],
							'message' => $sms_message,
							'template_code' => $template_code,
							'access_token' => $oct_sms_settings['oct_sms_token']
						));
					}
				}
			}
		}
	}

	private function sendMail($toEmail, $mailData) {
		$mail                 = new Mail($this->config->get('config_mail_engine'));
		$mail->protocol      = $this->config->get('config_mail_protocol');
		$mail->parameter     = $this->config->get('config_mail_parameter');
		$mail->smtp_hostname = $this->config->get('config_mail_smtp_hostname');
		$mail->smtp_username = $this->config->get('config_mail_smtp_username');
		$mail->smtp_password = html_entity_decode($this->config->get('config_mail_smtp_password'), ENT_QUOTES, 'UTF-8');
		$mail->smtp_port     = $this->config->get('config_mail_smtp_port');
		$mail->smtp_timeout  = $this->config->get('config_mail_smtp_timeout');

		$mail->setTo($toEmail);
		$mail->setFrom($this->config->get('config_email'));
		$mail->setSender(html_entity_decode($mailData['storeName'], ENT_QUOTES, 'UTF-8'));
		$mail->setSubject($mailData['subject']);
		
		if (!$mailData['type']) {
			$message = $mailData['welcome'] . "<br /><br />\n\n" . $mailData['body'] . "<br /><br /><br />\n\n" . $mailData['storeName'];
		} else {
			$message = html_entity_decode($mailData['welcome'] . "\n\n" . $mailData['storeName'], ENT_QUOTES, 'UTF-8');
		}

		$mail->setHtml($message);
		$mail->send();
	}
	
	private function prepareMailData($subscriber, $product) {
		$module_data = $this->config->get('oct_stock_notifier_data');
		$storeName = $this->config->get('config_name');
		$type = 0;

		$email_data = array();
		$email_data['product_link'] = $this->url->link('product/product', 'product_id=' . $product['product_id']);
		$email_data['product_name'] = htmlspecialchars($subscriber['name'], ENT_QUOTES, 'UTF-8');
		$email_data['store_name'] = htmlspecialchars($this->config->get('config_name'), ENT_QUOTES, 'UTF-8');
		$email_data['customer_name'] = htmlspecialchars($subscriber['customer_name'], ENT_QUOTES, 'UTF-8');

		if (isset($module_data['custom_message']) && $module_data['custom_message'] == "on") {
			$email_data['subject'] = $module_data['subject'][$subscriber['language_id']];
			$email_data['welcome'] = $module_data['message'][$subscriber['language_id']];
			$email_data['body'] = '';
			$type = 1;
			$this->convertHtmlMailData($email_data);
		} else {
			$email_data['subject'] = sprintf($this->language->get('mail_subject'), $email_data['store_name'], $email_data['product_name']);
			$email_data['welcome'] = sprintf($this->language->get('mail_welcome'), $email_data['store_name']);
			$email_data['body'] = sprintf($this->language->get('mail_body'), $email_data['product_name'], $email_data['product_link']);
		}

		return [
			'welcome' => $email_data['welcome'],
			'subject' => $email_data['subject'],
			'body' => $email_data['body'],
			'storeName' => $email_data['store_name'],
			'customerName' => $email_data['customer_name'],
			'productName' => $email_data['product_name'],
			'productLink' => $email_data['product_link'],
			'language_id' => (int) $subscriber['language_id'],
			'type' => $type
		];
	}

	private function convertHtmlMailData(&$data) {
        $data = str_replace(
            array(
				'[customer_name]',
                '[store]',
                '[product_name]',
                '[product_link]'
            ),
            array(
				$data['customer_name'],
                $data['store_name'],
                $data['product_name'],
                $data['product_link']
            ),
            $data
        );

        return $data;
    }

	private function notifyAdmin($data) {
		$this->language->load('octemplates/module/oct_stock_notifier');
		$this->load->model('catalog/product');

		$product_info = $this->model_catalog_product->getProduct((int)$data['pid']);

		$mailData = array();
		$storeName = $this->config->get('config_name');
		$mailData = array(
			'welcome' => htmlspecialchars(sprintf($this->language->get('mail_admin_welcome'), html_entity_decode($storeName, ENT_QUOTES, 'UTF-8')), ENT_QUOTES, 'UTF-8'),
			'subject' => htmlspecialchars(sprintf($this->language->get('mail_admin_subject'), html_entity_decode($storeName, ENT_QUOTES, 'UTF-8'), $product_info['name']), ENT_QUOTES, 'UTF-8'),
			'body' => htmlspecialchars(sprintf($this->language->get('mail_admin_body'), $product_info['name'], $this->url->link('product/product', 'product_id=' . $data['pid'])), ENT_QUOTES, 'UTF-8'),
			'productName' => htmlspecialchars($product_info['name'], ENT_QUOTES, 'UTF-8'),
			'storeName' => htmlspecialchars($storeName, ENT_QUOTES, 'UTF-8'),
			'type' => 0
		);

		$configData = $this->config->get('oct_stock_notifier_data');
		$emails = explode(',', $configData['email']);

		foreach ($emails as $email) {
			if ($email && filter_var(trim($email), FILTER_VALIDATE_EMAIL)) {
				$this->sendMail(trim($email), $mailData);
			}
		}

		$oct_sms_settings = $this->config->get('oct_sms_settings');
		$template_code = 'oct_stock_notifier_admin';
		$language_id = (int)$this->config->get('config_language_id');

		if (isset($oct_sms_settings['templates'][$template_code]['status']) && $oct_sms_settings['templates'][$template_code]['status']) {
			if (isset($oct_sms_settings['templates'][$template_code]['message'][$language_id]) && !empty($oct_sms_settings['templates'][$template_code]['message'][$language_id]) && isset($oct_sms_settings['templates'][$template_code]['edit_localization'])) {
				$sms_template = $oct_sms_settings['templates'][$template_code]['message'][$language_id];
			} else {
				$sms_template = $this->language->get('default_sms_template_admin');
			}

			if (!empty($sms_template)) {
				$customer_name = strip_tags($data['name']);
				$customer_name = mb_substr($customer_name, 0, 50);

				$product_name = strip_tags($product_info['name']);
				$product_name = mb_substr($product_name, 0, 100);

				$replace = array(
					'[customer_name]' => $customer_name,
					'[product_name]' => $product_name,
					'[product_link]' => $this->url->link('product/product', 'product_id=' . $data['pid']),
					'[store]' => $this->config->get('config_name')
				);

				$sms_message = str_replace(array_keys($replace), array_values($replace), $sms_template);

				if (!empty($oct_sms_settings['admin_phone']) && !empty($oct_sms_settings['oct_sms_token'])) {
					$this->load->model('octemplates/module/oct_sms_notify');

					$this->model_octemplates_module_oct_sms_notify->sendNotification(array(
						'phone' => $oct_sms_settings['admin_phone'],
						'message' => $sms_message,
						'template_code' => $template_code,
						'access_token' => $oct_sms_settings['oct_sms_token']
					));
				}
			}
		}
	}
	
	private function redirectToNotFound() {
		$this->response->redirect($this->url->link('error/not_found', '', true));
	}

	private function sanitizeString($input, $max_length = 255) {
		if (!is_string($input)) return '';
		$input = trim($input);
		$input = strip_tags($input);

		$input = preg_replace([
			'/[^\p{L}\p{N}\s\-_\.@]+/u',
			'/\s+/u'
		], ['', ' '], $input);

		return mb_substr($input, 0, $max_length, 'UTF-8');
	}

	protected function validate() {
		$oct_stock_notifier_data = $this->config->get('oct_stock_notifier_data');

		if (isset($this->request->post['name'])) {
			$this->request->post['name'] = $this->sanitizeString($this->request->post['name']);
		}
		if (isset($this->request->post['name']) && (isset($oct_stock_notifier_data['name']) && $oct_stock_notifier_data['name'] == 2) && (utf8_strlen(trim($this->request->post['name'])) < 1 || utf8_strlen(trim($this->request->post['name'])) > 32)) {
			$this->error['name'] = $this->language->get('error_name');
		}

		if (isset($this->request->post['phone'])) {
			$postedPhone = $this->request->post['phone'] ?? '';
			$oct_promo_data  = $this->config->get('theme_oct_promo_data');
			
			$cleanPhoneDigits = preg_replace('/[^0-9]/', '', $postedPhone);
			
			$phone_setting = $oct_stock_notifier_data['phone'] ?? '';

			if ($phone_setting == 2) {
				if (utf8_strlen($cleanPhoneDigits) < 3 || utf8_strlen($cleanPhoneDigits) > 15) {
					$this->error['phone'] = $this->language->get('error_phone');
				} else {
					$isValid = false;
					$hasAnyRegex = false;

					if (isset($oct_promo_data['phone_countries']) && is_array($oct_promo_data['phone_countries'])) {
						foreach ($oct_promo_data['phone_countries'] as $country) {
							if (!empty($country['regex'])) {
								$hasAnyRegex = true;
								$regex = $country['regex'];

								$regex = str_replace('\\+', '', $regex);

								if (substr($regex, 0, 1) !== '/') {
									$regex = '/' . $regex . '/';
								}

								if (@preg_match($regex, '') !== false) {
									if (preg_match($regex, $cleanPhoneDigits)) {
										$isValid = true;
										break;
									}
								}
							}
						}
					}
					
					if (!$hasAnyRegex) {
						$isValid = true;
					} elseif (!$isValid) {
						$this->error['phone'] = $this->language->get('error_phone_mask');
					}
				}
			}
		}

		if (isset($this->request->post['email']) && !filter_var($this->request->post['email'], FILTER_VALIDATE_EMAIL)) {
			$this->error['email'] = $this->language->get('error_email');
		}

		if ($this->config->get('config_account_id') && !isset($this->request->post['agree'])) {
			$this->load->model('catalog/information');

			$information_info = $this->model_catalog_information->getInformation($this->config->get('config_account_id'));
			if (isset($information_info) && !empty($information_info)) {
				$this->error['agree'] = sprintf($this->language->get('error_oct_terms'), $information_info['title']);
			}
		}

		return !$this->error;
	}

}