<?php

namespace Main\Controllers\GamingNight;

use Main\Core\Controller;
use Main\Core\Jobs\JobDispatcher;
use Main\Jobs\SendDiscordWebhook;
use Main\Services\DeliveryService;
use Main\Services\SeoService;
use Main\Services\SubscriptionService;
use PDO;
use Rakit\Validation\Validator;

class ProductController extends Controller
{
		protected string $route_type = 'gaming-night';
		
		public function __construct()
		{
			if (modules('gaming_night')->settings('day') != date("l") || date("Hi") < modules('gaming_night')->settings('start') || date("Hi") > modules('gaming_night')->settings('end')) {
				abort_404();
			}
		}
	
    public function show($id)
    {
        $product = db()->prepare("SELECT P.id, P.categoryID, P.name, P.price, P.duration, P.imageID, P.imageType, P.details, GNP.price as discountedPrice, GNP.stock FROM GamingNightProducts GNP INNER JOIN Products P ON GNP.productID = P.id WHERE GNP.productID = ? AND P.isActive = ?");
        $product->execute(array($id, 1));
        $product = $product->fetch();

        if (!$product) abort_404();
				
				$category = db()->prepare("SELECT * FROM ProductCategories WHERE id = ? AND isActive = ?");
				$category->execute(array($product["categoryID"], 1));
				$category = $category->fetch();
				
				if (!$category) abort_404();
				
				$product["category"] = $category;
	    
				SeoService::set('gaming-night.products.show', [
					'product_name' => $product['name'],
	      ]);
	    
		    $subscription = SubscriptionService::getSubscriptionByCategory($category);
				
		    $product["upgradable"] = $subscription != null && $product["priority"] < $subscription["priority"];
		    $product["downgradable"] = $subscription != null && $product["priority"] > $subscription["priority"];
		    $product["restricted"] = $subscription != null && $product["priority"] >= $subscription["priority"];
		    
		    $product["total"] = $product["discountedPrice"];
		    $product["subtotal"] = $product["price"];
		    $product["discount"] = $product["price"] - $product["discountedPrice"];
	    
	      $product["discountPercent"] = round((($product["price"]-$product["discountedPrice"])*100)/($product["price"]));
		    
		    $product["image"] = "/assets/core/images/store/products/" . $product["imageID"] . "." . $product["imageType"];
	    
		    $variables = db()->prepare("SELECT V.* FROM ProductVariables PV INNER JOIN StoreVariables V ON PV.variableID = V.id WHERE PV.productID = ?");
		    $variables->execute(array($product["id"]));
		    $product["variables"] = array_map(function ($variable) {
			    $variable["options"] = [];
			    if ($variable["type"] == "dropdown") {
				    $dropdownOptions = db()->prepare("SELECT * FROM StoreVariableDropdownOptions WHERE variableID = ?");
				    $dropdownOptions->execute(array($variable["id"]));
				    $variable["options"] = $dropdownOptions->fetchAll(PDO::FETCH_ASSOC);
			    }
			    
			    return $variable;
		    }, $variables->fetchAll(PDO::FETCH_ASSOC));
	    
		    if (request()->isAjax() || request()->isFormatAccepted('json')) {
			    response()->json([
				    'status' => true,
				    'html' => template()->render('modals/gaming-night-product', compact('product'))
			    ]);
		    }

        return $this->view('gaming-night.product', compact('product'));
    }

    public function buy($id)
    {
        $product = db()->prepare("SELECT P.id, P.name, P.price, P.categoryID, GNP.price as discountedPrice, GNP.stock, PC.name as categoryName, PC.isCumulative FROM GamingNightProducts GNP INNER JOIN Products P ON GNP.productID = P.id INNER JOIN ProductCategories PC ON P.categoryID = PC.id WHERE GNP.productID = ? AND P.isActive = ?");
        $product->execute(array($id, 1));
        $product = $product->fetch();
				
				if (!$product) abort_404();
				
				if ($product["stock"] == 0) {
					return back()->flash('error', t__('Out of stock!'));
				}
	    
		    $variables = db()->prepare("SELECT V.* FROM ProductVariables PV INNER JOIN StoreVariables V ON PV.variableID = V.id WHERE PV.productID = ?");
		    $variables->execute(array($product["id"]));
		    $product["variables"] = $variables->fetchAll(PDO::FETCH_ASSOC);
		    if (count($product["variables"]) > 0) {
			    foreach ($product["variables"] as $variable) {
				    // Validate variables
				    $rule = "required";
				    if ($variable["type"] == "number") {
					    $rule = "required|numeric";
				    }
				    if ($variable["type"] == "email") {
					    $rule = "required|email";
				    }
				    if ($variable["type"] == "url") {
					    $rule = "required|url";
				    }
				    if ($variable["type"] == "dropdown") {
					    $dropdownOptions = db()->prepare("SELECT * FROM StoreVariableDropdownOptions WHERE variableID = ?");
					    $dropdownOptions->execute(array($variable["id"]));
					    $dropdownOptions = $dropdownOptions->fetchAll(PDO::FETCH_ASSOC);
					    $validator = new Validator;
					    $rule = [
						    "required",
						    $validator('in', array_column($dropdownOptions, 'value'))
					    ];
				    }
				    validate([
					    'variable_' . $variable["id"] => $rule,
				    ]);
			    }
		    }
				
		    $subs = false;
		    if ($product["isCumulative"] == '1') {
			    $discountProducts = explode(",", modules('store')->settings('discountProducts'));
			    
			    $subs = db()->prepare("SELECT * FROM Subscriptions S INNER JOIN Products P ON P.id = S.productID WHERE P.categoryID = ? AND accountID = ? AND (endsAt > ? OR endsAt = '1000-01-01 00:00:00') ORDER BY P.priority ASC LIMIT 1");
			    $subs->execute(array($product["categoryID"], auth()->user()->id(), datetime()));
			    $subs = $subs->fetch(PDO::FETCH_ASSOC);
			    if ($subs) {
				    $searchSubsProductInGamingNight = db()->prepare("SELECT * FROM GamingNightProducts WHERE productID = ?");
				    $searchSubsProductInGamingNight->execute(array($subs["productID"]));
				    $searchSubsProductInGamingNight = $searchSubsProductInGamingNight->fetch();
				    if ($searchSubsProductInGamingNight)
					    $subs["price"] = $searchSubsProductInGamingNight["price"];
				    else if ($subs["discountedPrice"] > 0 && ($subs["discountExpiryDate"] > datetime() || $subs["discountExpiryDate"] == '1000-01-01 00:00:00'))
					    $subs["price"] = $subs["discountedPrice"];
				    else if (modules('store')->settings('discount') != 0 && (in_array($subs["productID"], $discountProducts) || modules('store')->settings('discountProducts') == '0') && (modules('store')->settings('discountExpiryDate') > datetime() || modules('store')->settings('discountExpiryDate') == '1000-01-01 00:00:00'))
					    $subs["price"] = ($subs["price"] * (100 - modules('store')->settings('discount'))) / 100;
			    }
		    }
		    
		    $price = $product["price"];
		    $discountedPrice = $product["discountedPrice"];
		    
		    if ($subs && $product["priority"] < $subs["priority"]) {
			    if ($subs["endsAt"] == '1000-01-01 00:00:00') {
				    $discountedPrice = $discountedPrice - $subs["price"];
			    } else {
				    $discountedPrice = $discountedPrice - (($subs["price"] * (strtotime($subs["endsAt"]) - time())) / (strtotime($subs["endsAt"]) - strtotime($subs["startsAt"])));
			    }
		    }
		    
		    // Block downgrading
		    if ($subs && $product["priority"] >= $subs["priority"]) {
			    return back();
		    }
		    
		    $total = $discountedPrice;
		    $subtotal = $price;
		    $discount = $subtotal - $total;
				
				// Add variable extra fees $total and $subtotal
	      $extraFee = 0;
				foreach ($product["variables"] as $variable) {
					if ($variable["type"] == "dropdown") {
						$selectedOption = db()->prepare("SELECT * FROM StoreVariableDropdownOptions WHERE variableID = ? AND `value` = ?");
						$selectedOption->execute(array($variable["id"], input('variable_' . $variable["id"])));
						$selectedOption = $selectedOption->fetch();
						if ($selectedOption) {
							$extraFee += $selectedOption["price"];
						}
					}
				}
				$subtotal += $extraFee;
		    $total += $extraFee;
				
				if (auth()->user()->data("credit") < $total) {
					return back()->flash('error', t__("You don't have enough credit."));
				}
	    
		    $createOrder = db()->prepare("INSERT INTO Orders (accountID, type, status, coupon, total, discount, subtotal, credit, paymentID, paymentAPI, creationDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
		    $createOrder->execute(array(auth()->user()->id(), 1, 1, null, $total, $discount, $subtotal, $total, "", "credit", datetime()));
		    $orderID = db()->lastInsertId();
		    $createOrderProducts = db()->prepare("INSERT INTO OrderProducts (orderID, productID, quantity, unitPrice) VALUES (?, ?, ?, ?)");
		    $createOrderProducts->execute(array($orderID, $product["id"], 1, $total));
				$orderProductID = db()->lastInsertId();
				
	      $insertOrderProductVariableValues = db()->prepare("INSERT INTO OrderProductVariableValues (orderProductID, variableID, value) VALUES (?, ?, ?)");
	      foreach ($product["variables"] as $variable) {
		      $insertOrderProductVariableValues->execute(array($orderProductID, $variable["id"], sanitize(input('variable_' . $variable["id"]))));
	      }
		    
		    $notificationsVariables = $product["categoryName"] . "," . $product["name"];
		    $insertNotifications = db()->prepare("INSERT INTO Notifications (accountID, type, variables, creationDate) VALUES (?, ?, ?, ?)");
		    $insertNotifications->execute(array(auth()->user()->id(), 4, $notificationsVariables, datetime()));
		    
		    JobDispatcher::dispatch((new SendDiscordWebhook('store.purchase.product', [
			    "username" => auth()->user()->displayName(),
			    "product" => $product["name"],
			    "category" => $product["categoryName"],
			    "quantity" => 1,
			    "price" => $total,
			    "currency" => settings('currency'),
		    ])));
		    
		    $updateCredit = db()->prepare("UPDATE Accounts SET credit = credit - ? WHERE id = ?");
		    $updateCredit->execute(array($total, auth()->user()->id()));
		    
		    if (!modules('chest')->isActive()) {
					$variablesForDelivery = [];
					foreach ($product["variables"] as $variable) {
						$variablesForDelivery[$variable["identifier"]] = sanitize(input('variable_' . $variable["id"]));
					}
					
			    DeliveryService::deliver(
				    [[
					    'id' => $product["id"],
					    'quantity' => 1,
					    'variables' => $variablesForDelivery
				    ]],
				    auth()->user()->id(),
				    "order",
				    $orderID,
			    );
		    } else {
			    $insertChests = db()->prepare("INSERT INTO Chests (accountID, productID, status, creationDate) VALUES (?, ?, ?, ?)");
			    $insertChests->execute(array(auth()->user()->id(), $product["id"], 0, datetime()));
					$chestID = db()->lastInsertId();
					
			    $insertChestProductVariableValues = db()->prepare("INSERT INTO ChestProductVariableValues (chestID, variableID, value) VALUES (?, ?, ?)");
			    foreach ($product["variables"] as $variable) {
				    $insertChestProductVariableValues->execute(array($chestID, $variable["id"], sanitize(input('variable_' . $variable["id"]))));
			    }
		    }
		    
		    if ($product["stock"] != -1) {
			    $updateStock = db()->prepare("UPDATE GamingNightProducts SET stock = stock - 1 WHERE productID = ?");
			    $updateStock->execute(array($product["id"]));
		    }
		    
		    if (modules('chest')->isActive()) {
			    return back()->flash('success', t__('Your purchase has been completed and added to your chest.'));
		    }
	    
		    return back()->flash('success', t__('The product has been successfully delivered! Have fun!'));
    }
}