<?php

namespace Main\Controllers\Credit;

use Main\Core\Controller;
use Main\Services\SeoService;
use PDO;

class SendCreditController extends Controller
{
		protected string $route_type = 'send-credits';
	
		public function __construct()
		{
			if (modules('credit')->settings('canSendCredits') == 0) abort_404();
		}
		
    public function index()
    {
	      SeoService::set('credits.send.index');
				
        $logs = db()->prepare("SELECT CH.*, A.username, A.realname as otherAccountDisplayName FROM CreditHistory CH LEFT JOIN Accounts A ON A.id = CH.otherAccountID WHERE CH.accountID = ? AND CH.type IN (?, ?) ORDER by CH.id DESC LIMIT 5");
		    $logs->execute(array(auth()->user()->id(), 3, 4));
		    $logs = $logs->fetchAll();

        return $this->view('credits.send', compact('logs'));
    }

    public function to($id)
    {
		    $target = db()->prepare("SELECT * FROM Accounts WHERE id = ?");
		    $target->execute(array($id));
		    $target = $target->fetch();
				
				if (!$target) abort_404();
				
				$target["uniqueIdentifier"] = settings('gameType') == 'minecraft' ? $target["realname"] : $target["username"];
	    
		    SeoService::set('credits.send.to', [
					'username' => $target['realname']
		    ]);
	    
		    $logs = db()->prepare("SELECT CH.*, A.username, A.realname as otherAccountDisplayName FROM CreditHistory CH LEFT JOIN Accounts A ON A.id = CH.otherAccountID WHERE CH.accountID = ? AND CH.type IN (?, ?) ORDER by CH.id DESC LIMIT 5");
		    $logs->execute(array(auth()->user()->id(), 3, 4));
		    $logs = $logs->fetchAll();

        return $this->view('credits.send', compact('target', 'logs'));
    }
	
		public function send()
		{
				// Validate user input
				validate([
					'username' => 'required',
					'amount' => 'required|numeric|min:1',
				]);
				
				$amount = input("amount");
				$username = sanitize(input("username"));
				
				// Determine the correct column for username lookup based on game type
				if (settings('gameType') == 'minecraft') { // Xbox Login (username => uuid / realname => username)
					$receiverAccount = db()->prepare("SELECT * FROM Accounts WHERE realname = ?");
				} else {
					$receiverAccount = db()->prepare("SELECT * FROM Accounts WHERE username = ?");
				}
				$receiverAccount->execute([$username]);
				$receiverAccount = $receiverAccount->fetch();
				
				// Check if the receiver account exists
				if (!$receiverAccount) {
					return back()->flash('error', t__('<strong>%username%</strong> not found!', ['%username%' => $username]));
				}
				
				// Prevent the user from sending credits to themselves
				if (auth()->user()->id() == $receiverAccount["id"]) {
					return back()->flash('error', t__("You can't send credits to yourself!"));
				}
				
				// Check if the sender has enough credits
				if ($amount > auth()->user()->data("credit")) {
					return back()->flash('error', t__("You don't have enough credits!"));
				}
				
				db()->beginTransaction();
				
				// Lock the sender's account to prevent race conditions
				$getSenderAccount = db()->prepare("SELECT credit FROM Accounts WHERE id = :sender FOR UPDATE");
				$getSenderAccount->execute([
					":sender" => auth()->user()->id()
				]);
				$senderAccount = $getSenderAccount->fetch(PDO::FETCH_ASSOC);
				
				// Ensure the sender still has enough balance after locking the row
				if (!$senderAccount || $senderAccount["credit"] < $amount) {
					db()->rollBack();
					return back()->flash('error', t__("You don't have enough credits!"));
				}
				
				// Lock the receiver's account to prevent race conditions
				$getReceiverAccount = db()->prepare("SELECT credit FROM Accounts WHERE id = :receiver FOR UPDATE");
				$getReceiverAccount->execute([":receiver" => $receiverAccount["id"]]);
				$receiverAccountData = $getReceiverAccount->fetch(PDO::FETCH_ASSOC);
				
				if (!$receiverAccountData) {
					db()->rollBack();
					return back()->flash('error', t__('<strong>%username%</strong> not found!', ['%username%' => $username]));
				}
				
				// Deduct credit from sender
				$updateSenderAccount = db()->prepare("UPDATE Accounts SET credit = credit - :amount WHERE id = :sender");
				$updateSenderAccount = $updateSenderAccount->execute([
					":amount" => $amount,
					":sender" => auth()->user()->id()
				]);
				
				// Add credit to receiver
				$updateReceiverAccount = db()->prepare("UPDATE Accounts SET credit = credit + :amount WHERE id = :receiver");
				$updateReceiverAccount = $updateReceiverAccount->execute([
					":amount" => $amount,
					":receiver" => $receiverAccount["id"]
				]);
				
				// Insert transaction history
				$insertCreditHistory = db()->prepare("INSERT INTO CreditHistory (accountID, otherAccountID, type, price, creationDate) VALUES (?, ?, ?, ?, ?)");
				$insertCreditHistoryForSender = $insertCreditHistory->execute([
					auth()->user()->id(),
					$receiverAccount["id"],
					3,
					$amount,
					datetime()
				]);
				
				$insertCreditHistoryForReceiver = $insertCreditHistory->execute([
					$receiverAccount["id"],
					auth()->user()->id(),
					4,
					$amount,
					datetime()
				]);
				
				// Commit the transaction if all steps are successful
				if ($updateSenderAccount && $updateReceiverAccount && $insertCreditHistoryForSender && $insertCreditHistoryForReceiver) {
					db()->commit();
					return back()->flash('success', t__('%credit% credit(s) have been successfully sent to %username%!', [
						'%credit%' => $amount,
						'%username%' => $username
					]));
				} else {
					db()->rollBack();
					return back()->flash('error', t__('Something went wrong! Please try again later.'));
				}
		}
}