<?php
namespace SGC\eGiftCard\Hooks\Handler;

defined('ABSPATH') || exit; // Prevent direct file access

use SGC\eGiftCard\Http\Model\GiftCode;
use SGC\eGiftCard\Http\Model\UserBalance;
use SGC\eGiftCard\Foundation\Application;
use SGC\eGiftCard\Services\Mailer;

class ActionHooksHandler
{

    /**
     * Set custom gift card price in cart.
     *
     * @param WC_Cart $cart Cart object.
     */
    public static function set_custom_gift_card_price($cart)
    {
        foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
            if (isset($cart_item['gift_card_data'])) {
                $custom_price = floatval($cart_item['gift_card_data']['gift_amount']);
                $cart_item['data']->set_price($custom_price);
            }
        }
    }

    /**
     * Save gift card data in order.
     *
     * @param WC_Order_Item $item Order item object.
     * @param string        $cart_item_key Cart item key.
     * @param array         $values Cart values.
     * @param WC_Order      $order Order object.
     */
    public static function save_gift_card_data_in_order($item, $cart_item_key, $values, $order)
    {
        if (isset($values['gift_card_data'])) {
            $gift_card_data = $values['gift_card_data'];

            if( ! empty( $gift_card_data ) ) {
                $raw_code       = strtoupper(substr(md5(uniqid()), 0, 16));
                $chunks         = str_split($raw_code, 4);
                $gift_code      = implode('-', $chunks);
                $giftCode       = GiftCode::getInstance();
                $app = Application::instance();
                // Fetch the general settings for the gift card plugin
                $settings = $app->getOption('sgc_smart_gift_general_settings', []);
                $validy_years   = isset($settings['code_validation']) ? $settings['code_validation'] : 5;

                // Prepare the gift code data.
                $data = array(
                    'gift_code'        => $gift_code,
                    'order_id'         => 0,
                    'sender_name'      => sanitize_text_field( $gift_card_data['sender_name'] ),
                    'recipient_email'  => sanitize_email( $gift_card_data['recipient_email'] ),
                    'recipient_name'   => sanitize_text_field( $gift_card_data['recipient_name'] ),
                    'gift_message'     => sanitize_textarea_field( $gift_card_data['gift_message'] ),
                    'gift_amount'      => floatval( $gift_card_data['gift_amount'] ),
                    'delivery_date'    => sanitize_text_field( $gift_card_data['delivery_date'] ),
                    'is_delivered'     => 0,
                    'design_url'       => sanitize_text_field( $gift_card_data['design_url'] ),
                    'created_at'       => current_time('mysql'),
                    'expires_at'       => gmdate('Y-m-d H:i:s', strtotime("+$validy_years  years")),
                    'is_redeemed'      => 0,
                );

                $giftCode->store($data);
            }

            $item->add_meta_data('Sender Name', $gift_card_data['sender_name']);
            $item->add_meta_data('Recipient Name', $gift_card_data['recipient_name']);
            $item->add_meta_data('Recipient Email', $gift_card_data['recipient_email']);
            $item->add_meta_data('Delivery Date', $gift_card_data['delivery_date']);
        }
    }

    /**
     * Generate gift code on order completion.
     *
     * @param int $order_id Order ID.
     */
    public static function generate_gift_code_on_order_complete($order_id)
    {
        global $wpdb;
        $order = wc_get_order($order_id);

        foreach ($order->get_items() as $item_id => $item) {
            if ($item->get_meta('Recipient Email')) {
                $recipient_email = $item->get_meta('Recipient Email');
                $recipient_name = $item->get_meta('Recipient Name');
                $sender_name = $item->get_meta('Sender Name');
                $delivery_date = $item->get_meta('Delivery Date');
                //@codingStandardsIgnoreStart
                //Fetch the gift card code from the database
                $giftItem = $wpdb->get_row(
                    $wpdb->prepare(
                        "SELECT * FROM {$wpdb->prefix}gift_codes WHERE sender_name = %s AND recipient_email = %s AND recipient_name = %s AND delivery_date = %s AND order_id = 0",
                        $sender_name, $recipient_email, $recipient_name, $delivery_date
                    )
                ); 
                // @codingStandardsIgnoreEnd                                     

                if ( empty($giftItem)) {
                    continue;
                }

                $row_id = $giftItem->id;
                //@codingStandardsIgnoreStart
                // Update the gift code with the order ID
                $wpdb->query(
                    $wpdb->prepare(
                        "UPDATE {$wpdb->prefix}gift_codes SET order_id = %d WHERE id = %d",
                        $order_id,
                        $row_id
                    )
                );
                // @codingStandardsIgnoreEnd
                $giftItem->order_id = $order_id;

                do_action('sgc_smart_gift_card_data_after_confirm_order', $giftItem);
            }
        }
    }

    /**
     * Apply gift card balance to the cart.
     */
    public static function apply_gift_card_balance()
    {
        $user_id = get_current_user_id();
        $use_gift_balance = get_user_meta($user_id, 'use_gift_balance', true);

        if ('no' !== $use_gift_balance) {
            $userBalanceModel = UserBalance::getInstance();
            $user_balance = $userBalanceModel->getBalanceByUserId($user_id);
            $cart_total = WC()->cart->get_subtotal();

            if ($cart_total > 0 && $user_balance > 0) {
                $balance_used = min($user_balance, $cart_total);
                WC()->cart->add_fee(__('Gift Wallet Balance', 'smart-gift-card'), -$balance_used);

                // Mark the session that a gift card was used
                WC()->session->set('gift_card_used', true);
                WC()->session->set('gift_card_used_balance', $balance_used);
            }
        }
    }

    /**
     * Update the user's gift card balance after a purchase.
     *
     * This function checks if the user has opted to use their gift card balance
     * and deducts the appropriate amount from their balance after the order is placed.
     *
     * @param int $order_id The ID of the completed order.
     */
    public static function update_gift_card_balance_after_purchase($order_id)
    {
        // Get the current user ID.
        $user_id = get_current_user_id();

        // Retrieve the 'use_gift_balance' user meta.
        $use_gift_balance = get_user_meta($user_id, 'use_gift_balance', true);

        // Proceed if the user has opted to use the gift balance.
        if ('no' === $use_gift_balance) {
            return;
        }

        // Get the user's current gift card balance.
        $userBalanceModel = UserBalance::getInstance();
        $user_balance = $userBalanceModel->getBalanceByUserId($user_id);

        // Get the order object.
        $order = wc_get_order($order_id);

        // Calculate the total discount applied in the order.
        $total_discount = 0;
        foreach ($order->get_items() as $item) {
            $total_discount += (float) $item->get_total(); // Get the total amount from the order item
        }

        if ($total_discount <= 0 || $user_balance <= 0) {
            return;
        }

        // Retrieve session data for gift card usage and balance used.
        $gift_card_used = WC()->session->get('gift_card_used');
        $gift_used_balance = WC()->session->get('gift_card_used_balance');

        // Calculate the amount to be used from the gift card balance.
        $amount_used = min($user_balance, $total_discount);

        // If the gift card was used and the used balance matches, deduct the balance.
        if ($gift_card_used && $amount_used == $gift_used_balance) {
            // Update the user's balance in the database.
            $new_balance = $user_balance - $amount_used;

            $userBalanceModel->updateBalance($user_id, $new_balance);
        }
    }

    /**
     * Retrieves the customer's email address based on the WooCommerce order ID.
     *
     * This function performs a custom query to fetch the email address associated 
     * with the given order ID by looking up the '_billing_email' meta field in 
     * the wp_postmeta table.
     *
     * @param int $order_id The WooCommerce order ID.
     * @return string The customer's email address if found, otherwise an empty string.
     */
    public static function get_customer_email_from_order_id( $order_id )
    {
        global $wpdb;

        // Sanitize the order ID before using it in the query
        $order_id = intval($order_id);
        // Prepare and execute the query to retrieve the billing email for the order
        //@codingStandardsIgnoreStart
        $email = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT meta_value 
                FROM {$wpdb->postmeta} 
                WHERE post_id = %d 
                AND meta_key = '_billing_email'", 
                $order_id
            )
        );
        //@codingStandardsIgnoreEnd
        // Return the email if found, otherwise return an empty string
        return $email ? $email : '';
    }

    /**
     * Processes and sends gift cards that are scheduled for delivery.
     * 
     * This function retrieves all gift cards from the database that have a delivery date of today or earlier 
     * and have not yet been delivered. It then sends the gift card via email to the recipient and updates the 
     * database to mark the gift card as delivered.
     * 
     * @global wpdb $wpdb WordPress Database Access abstraction object.
     * 
     * @return void
     */
    public static function gift_card_hourly_tasks()
    {
        global $wpdb;
        // Get the current date in 'Y-m-d' format
        $now = gmdate('Y-m-d');

        // Retrieve all undelivered gift codes with a delivery date of today or earlier
        //@codingStandardsIgnoreStart
        $gift_codes = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}gift_codes WHERE delivery_date <= %s AND is_delivered = 0 AND is_redeemed = 0 AND order_id != 0",
                $now
            )
        );
        //@codingStandardsIgnoreEnd
        // If no gift codes are found, exit the function
        if (empty($gift_codes)) {
            return;
        }

        // Get brand details like logo and name
        $brand_details = self::get_brand_details();

        // Loop through each undelivered gift code and send the gift email
        foreach ($gift_codes as $data) {
            // Send the gift card email
            self::send_gift_card_email($data, $brand_details);

            //Send email to gift sender
            self::send_email_to_gift_sender($data, $brand_details);

            // Mark the gift code as delivered in the database
            //@codingStandardsIgnoreStart
            $wpdb->update(
                "{$wpdb->prefix}gift_codes",
                array('is_delivered' => 1),
                array('id' => $data->id)
            );
            //@codingStandardsIgnoreEnd
        }
    }

    /**
     * Sends a gift card email to the recipient if the gift card is scheduled for delivery and hasn't been delivered yet.
     * 
     * This function checks if the gift card's delivery date is today or earlier and if it has not been delivered. 
     * If both conditions are met, it sends the gift card email to the recipient and marks the gift code as delivered in the database.
     * 
     * @global wpdb $wpdb WordPress Database Access abstraction object.
     * 
     * @param object $data Gift card data including recipient, sender, gift message, gift amount, and delivery status.
     * 
     * @return void
     */
    public static function gift_code_created($data)
    {
        //Return is data is empty
        if (empty($data)) {
            return;
        }

        // Exit if the gift card has already been delivered
        if ( $data->is_delivered ) {
            return;
        }

        global $wpdb;

        // Get the current date in 'Y-m-d' format
        $now = gmdate('Y-m-d');

        // Check if the gift card's delivery date is today or earlier
        if (strtotime($data->delivery_date) <= strtotime($now)) {
            // Get brand details like logo and name
            $brand_details = self::get_brand_details();

            // Send the gift card email
            self::send_gift_card_email( $data, $brand_details);

            //Send email to gift sender
            self::send_email_to_gift_sender($data, $brand_details);

            // Mark the gift code as delivered in the database
            //@codingStandardsIgnoreStart
            $wpdb->update(
                "{$wpdb->prefix}gift_codes",
                array('is_delivered' => 1),
                array('id' => $data->id)
            );
            //@codingStandardsIgnoreEnd
        }
    }

    /**
     * Auto-complete orders that contain only gift cards.
     *
     * @param int $order_id The ID of the order being processed.
     * @return void
     */
    public static function auto_complete_gift_card_orders( $order_id ) 
    {
        if ( ! $order_id ) {
            return;
        }

        // Get order
        $order = wc_get_order($order_id);
        
        // Skip if order is already completed
        if ( $order->get_status() === 'completed' ) {
            return;
        }
        
        // Check if order contains only gift cards
        $contains_only_gift_cards = true;
        $contains_gift_card = false;
        
        foreach ($order->get_items() as $item) {
            if ($item->get_meta('Recipient Email')) {
                // This is a gift card
                $contains_gift_card = true;
            } else {
                // This is not a gift card
                $contains_only_gift_cards = false;
            }
        }
        
        // If order contains at least one gift card and nothing else, mark as completed
        if ($contains_gift_card && $contains_only_gift_cards) {
            // Add note to the order
            $order->add_order_note(__('Order automatically completed as it contains only gift cards.', 'smart-gift-card'));
            
            // Update order status to completed
            $order->update_status('completed');
        }
    }

    /**
     * Retrieves brand details including the logo and brand name.
     * 
     * @return array Contains 'brand_logo' and 'brand_name' values.
     */
    private static function get_brand_details()
    {
        $upload_dir = wp_upload_dir();
        $uploadUrl  = esc_url($upload_dir['baseurl']) . '/' . SMART_GIFT_CARD_PLUGIN_ASSET_ID;
        // Use the instance of Application class to call the getOption method
        $app = Application::instance();
        // Fetch the general settings for the gift card plugin
        $settings = $app->getOption('sgc_smart_gift_general_settings', []);

        // Determine the brand logo URL, defaulting to 'logo.png' if not specified in the settings
        $brand_logo = isset($settings['brand_logo']) && !empty($settings['brand_logo'])
            ? $settings['brand_logo']
            : 'logo.png';
        if (!empty($settings) && isset($settings['redeem_gift_page_id'])) {
            $page_id = $settings['redeem_gift_page_id'];
            $page = get_post($page_id);
            $redeem_gift_page = home_url($page->post_name);
        } else {
            $redeem_gift_page = home_url();
        }

        $brand_logo = $uploadUrl . '/' . $brand_logo;
        $brand_name = get_bloginfo('name') . __(' eGift Card', 'smart-gift-card');

        return [
            'brand_logo' => $brand_logo,
            'brand_name' => $brand_name,
            'upload_url' => esc_url($upload_dir['baseurl']) . '/' . SMART_GIFT_CARD_PLUGIN_ASSET_ID,
            'redeem_gift_page' => $redeem_gift_page
        ];
    }

    /**
     * Sends the gift card email to the recipient.
     * 
     * @param object $data Gift card data object containing recipient details, message, and more.
     * @param array $brand_details Brand details like logo and name.
     * 
     * @return void
     */
    private static function send_gift_card_email($data, $brand_details)
    {
        $design_url = $data->design_url;
        if (strpos( $data->design_url, '_temp_') === 0) {
            $parts = explode('_temp_', $data->design_url);
            $design_url = '_temp'. '/' . end($parts);
        } else {
            $design_url = $data->design_url;
        }

        $img_url =  self::get_img_url();

        Mailer::send_gift_email([
            'receiver_name'    => $data->recipient_name,
            'sender_name'      => $data->sender_name,
            'selected_image'   => esc_url( $img_url . '/' . $design_url ),
            'gift_message'     => $data->gift_message,
            'gift_amount'      => $data->gift_amount,
            'brand_name'       => $brand_details['brand_name'],
            'brand_logo'       => $brand_details['brand_logo'],
            'gift_code'        => $data->gift_code,
            'to_email'         => $data->recipient_email,
            'redeem_gift_page' => $brand_details['redeem_gift_page'],
        ]);
    }

    private static function send_email_to_gift_sender($data, $brand_details)
    {
        $order_id = $data->order_id;
        $upload_dir = wp_upload_dir();

        // Get the customer's email address based on the order ID
        $customer_email = self::get_customer_email_from_order_id($order_id);

        if( ! empty( $customer_email ) ) {
            $design_url = $data->design_url;
            $date = new \DateTime($data->created_at);
            $purchased_date = $date->format('F j, Y');

            $d_date = new \DateTime($data->delivery_date);
            $delivery_date = $d_date->format('F j, Y');

            if (strpos( $data->design_url, '_temp_') === 0) {
                $parts = explode('_temp_', $data->design_url);
                $design_url = '_temp'. '/' . end($parts);
            } else {
                $design_url = $data->design_url;
            }

            $img_url =  self::get_img_url();

            Mailer::send_email_to_gift_sender([
                'receiver_name'    => $data->recipient_name,
                'receiver_email'   => $data->recipient_email,
                'sender_name'      => $data->sender_name,
                'purchased_date'   => $purchased_date,
                'delivery_date'    => $delivery_date,
                'selected_image'   => esc_url( $img_url . '/' . $design_url ),
                'gift_message'     => $data->gift_message,
                'gift_amount'      => $data->gift_amount,
                'brand_name'       => $brand_details['brand_name'],
                'brand_logo'       => $brand_details['brand_logo'],
                'to_email'         => $customer_email
            ]);
        }
    }

    private static function get_img_url() 
    {
        if( defined('SMART_GIFT_CARD_PLUGIN_PRO') ) {
            $upload_dir = wp_upload_dir();
            return esc_url( $upload_dir['baseurl']) . '/' . SMART_GIFT_CARD_PLUGIN_ASSET_ID;
        } else {
            return esc_url( SMART_GIFT_CARD_PLUGIN_URL . '/assets/img' );
        }
    }
}
