<?php

namespace Pixeldev\SquareWooSync\Woo;

if (!defined('ABSPATH')) {
  exit; // Exit if accessed directly
}

use Pixeldev\SquareWooSync\REST\SquareController;
use Pixeldev\SquareWooSync\Square\SquareHelper;

class CreateOrder
{
  private $square_customer_data = null;
  private $square_helper;
  private $settings;

  public function __construct()
  {
    $this->square_helper = new SquareHelper();
    // Fetch plugin settings
    $this->settings = get_option('square-woo-sync_settings', []);
  }

  public function process_square_order($body)
  {
    $this->square_customer_data = null;
    // Extract order ID from the payload
    $orderId = $body['data']['object']['order_created']['order_id'];



    // Use WooCommerce's `wc_get_orders` to find the order by `square_order_id`
    $args = [
      'numberposts' => 1,
      'meta_key'    => 'square_order_id',
      'meta_value'  => $orderId,
      'meta_compare' => '=',
      'return'      => 'ids'
    ];

    $order_ids = wc_get_orders($args);

    if (!empty($order_ids)) {
      return;
    }

    // Fetch the order from Square
    $squareOrder = $this->get_square_order($orderId);

    if ($squareOrder) {
      // Create a WooCommerce order
      $this->create_woocommerce_order($squareOrder);

    } else {
      error_log('Failed to fetch order from Square with ID: ' . $orderId);
    }
  }

  private function get_square_order($orderId)
  {
    $endpoint = '/orders/' . $orderId;
    $response = $this->square_helper->square_api_request($endpoint, 'GET');

    if ($response['success']) {
      return $response['data']['order'];
    } else {
      error_log('Error fetching order from Square: ' . $response['error']);
      return null;
    }
  }

  private function create_woocommerce_order($squareOrder)
  {
    // Create new WooCommerce order
    $order = wc_create_order();

    $square_data = ['order' => ['success' => true, 'data' => ['order' => $squareOrder]]];
    $order->update_meta_data('square_data', wp_json_encode($square_data));
    $order->update_meta_data('square_order_id',  $squareOrder['id']);
    $order->save();



    // Set customer details
    $customerId = $this->get_customer_id($squareOrder);
    if ($customerId) {
      $order->set_customer_id($customerId);
    } else {
      // Guest customer; use Square customer data to set billing/shipping details
      if (isset($this->square_customer_data)) {
        $this->set_addresses($order, $squareOrder, $this->square_customer_data);
      }
    }

    // Add order items
    $this->add_order_items($order, $squareOrder);

    // Apply taxes and discounts
    $this->apply_order_taxes_and_discounts($order, $squareOrder);

    // Set order totals
    $this->set_order_totals($order, $squareOrder);

    // Set payment method
    $order->set_payment_method('square');

    // Handle fulfillments
    $this->handle_fulfillments($order, $squareOrder);

    // Set order status
    $this->set_order_status($order, $squareOrder);

    // Save the order
    $order->save();

    do_action( 
      'squarewoosync_square_order_imported', 
      $squareOrder['id'], 
      $order->get_id() 
    );

    return $order;
  }

  private function set_order_totals($order, $squareOrder)
  {
    $totalAmount = isset($squareOrder['total_money']['amount']) ? $squareOrder['total_money']['amount'] / 100 : 0;
    $totalTax = isset($squareOrder['total_tax_money']['amount']) ? $squareOrder['total_tax_money']['amount'] / 100 : 0;

    $order->set_total($totalAmount);

    // Set cart tax using the public method
    $order->set_cart_tax($totalTax);

    // Set cart discount total
    $totalDiscount = isset($squareOrder['total_discount_money']['amount']) ? $squareOrder['total_discount_money']['amount'] / 100 : 0;
    $order->set_discount_total($totalDiscount);
  }

  private function set_order_meta($wc_order, $squareOrder)
  {

    $square_data = ['order' => ['success' => true, 'data' => ['order' => $squareOrder]]];
    $wc_order->update_meta_data('square_data', wp_json_encode($square_data));
    $wc_order->update_meta_data('square_order_id',  $squareOrder['id']);
    $wc_order->save();
  }

  private function get_customer_id($squareOrder)
  {
    // Retrieve customer ID from Square order
    $squareCustomerId = isset($squareOrder['customer_id']) ? $squareOrder['customer_id'] : null;
    if ($squareCustomerId) {
      // Logic to find matching WooCommerce customer
      $args = array(
        'meta_key'   => '_square_customer_id',
        'meta_value' => $squareCustomerId,
        'number'     => 1,
        'fields'     => 'ID',
      );
      $user_query = new \WP_User_Query($args);
      $users = $user_query->get_results();

      if (!empty($users)) {
        // Matching WooCommerce customer found
        return $users[0];
      } else {
        // No matching WooCommerce customer found
        // Fetch Square customer details
        $squareCustomerData = $this->get_square_customer($squareCustomerId);
        if ($squareCustomerData) {
          // Store customer data for later use
          $this->square_customer_data = $squareCustomerData;
        }
      }
    }

    // Return 0 to indicate guest customer
    return 0;
  }

  private function get_square_customer($squareCustomerId)
  {
    $endpoint = '/customers/' . $squareCustomerId;
    $response = $this->square_helper->square_api_request($endpoint, 'GET');

    if ($response['success']) {
      return $response['data']['customer'];
    } else {
      error_log('Error fetching customer from Square: ' . $response['error']);
      return null;
    }
  }

  private function add_order_items($order, $squareOrder)
  {
    $lineItems = isset($squareOrder['line_items']) ? $squareOrder['line_items'] : [];
    if ($lineItems) {
      foreach ($lineItems as $lineItem) {
        // Fetch Square product details
        $squareProductDetails = $this->square_helper->get_square_item_details($lineItem['catalog_object_id']);
        if ($squareProductDetails) {
          // Check if product exists in WooCommerce
          $product = $this->get_woocommerce_product($squareProductDetails);
          if ($product) {
            // Add existing product to order
            $this->add_existing_product_to_order($order, $product, $lineItem, $squareProductDetails);
          } else {
            // Add custom order item
            $this->add_custom_order_item($order, $lineItem, $squareProductDetails);
          }
        } else {
          error_log('Failed to fetch Square product details for ID: ' . $lineItem['catalog_object_id']);
          // Optionally, handle this case (e.g., skip the item or add it as a custom item)
        }
      }
    }
  }

  private function get_woocommerce_product($squareProductDetails)
  {
    $squareController = new SquareController();
    $squareProductId = $squareProductDetails['object']['id'] ?? null;
    $squareVariationId = null;

    if ($squareProductDetails['object']['type'] === 'ITEM_VARIATION') {
      $squareVariationId = $squareProductId;
      $squareProductId = $squareProductDetails['object']['item_variation_data']['item_id'];
    }

    // Use the get_woocommerce_products_square method
    $woocommerceProducts = $squareController->get_woocommerce_products_square($squareProductId, $squareVariationId);

    if (!empty($woocommerceProducts)) {
      $productId = $woocommerceProducts[0]['ID'];
      return wc_get_product($productId);
    }

    return null;
  }

  private function add_existing_product_to_order($order, $product, $lineItem, $squareProductDetails)
  {
    $quantity = intval($lineItem['quantity']);

    // Add the product to the order
    $order_item_id = $order->add_product($product, $quantity);

    // Get the order item
    $order_item = $order->get_item($order_item_id);

    // Get base price
    $basePrice = isset($lineItem['base_price_money']['amount']) ? $lineItem['base_price_money']['amount'] / 100 : 0;

    // Calculate subtotal (base price * quantity)
    $subtotal = $basePrice * $quantity;

    // Get total discount for this line item
    $lineItemDiscount = isset($lineItem['total_discount_money']['amount']) ? $lineItem['total_discount_money']['amount'] / 100 : 0;

    // Calculate total (subtotal - discount)
    $total = $subtotal - $lineItemDiscount;

    // Set subtotal and total
    $order_item->set_subtotal($subtotal);
    $order_item->set_total($total);

    // Add meta data if needed
    $order_item->add_meta_data('_square_item_data', $squareProductDetails, true);
    $order_item->add_meta_data('_square_line_item_discount', $lineItemDiscount, true);

    $order_item->save();
  }

  private function add_custom_order_item($order, $lineItem, $squareProductDetails)
  {

    // Create a new order item of type 'line_item'
    $item = new \WC_Order_Item_Product();

    // Set item name from Square product details
    $itemName = isset($squareProductDetails['object']['item_data']['name']) 
    ? $squareProductDetails['object']['item_data']['name'] . (!empty($lineItem['variation_name']) ? ' - ' . $lineItem['variation_name'] : '') 
    : $lineItem['name'] . (!empty($lineItem['variation_name']) ? ' - ' . $lineItem['variation_name'] : '');

    $item->set_name($itemName);

    // Set the quantity
    $quantity = intval($lineItem['quantity']);
    $item->set_quantity($quantity);

    // Get base price
    $basePrice = isset($lineItem['base_price_money']['amount']) ? $lineItem['base_price_money']['amount'] / 100 : 0;

    // Calculate subtotal (base price * quantity)
    $subtotal = $basePrice * $quantity;

    // Get total discount for this line item
    $lineItemDiscount = isset($lineItem['total_discount_money']['amount']) ? $lineItem['total_discount_money']['amount'] / 100 : 0;

    // Calculate total (subtotal - discount)
    $total = $subtotal - $lineItemDiscount;

    // Set subtotal and total
    $item->set_subtotal($subtotal);
    $item->set_total($total);

    // Add meta data if needed
    $item->add_meta_data('_square_item_id', $lineItem['catalog_object_id'], true);

    if (isset($squareProductDetails['object']['item_variation_data']['sku'])) {
      $item->add_meta_data('_sku', $squareProductDetails['object']['item_variation_data']['sku'], true);
    }

    $item->add_meta_data('_square_item_data', $squareProductDetails, true);
    $item->add_meta_data('_square_line_item_discount', $lineItemDiscount, true);

    // Add the item to the order
    $order->add_item($item);
  }

  private function apply_order_taxes_and_discounts($order, $squareOrder)
  {
    // Handle Taxes
    if (isset($squareOrder['taxes']) && !empty($squareOrder['taxes'])) {
      foreach ($squareOrder['taxes'] as $tax) {
        $taxAmount = isset($tax['applied_money']['amount']) ? $tax['applied_money']['amount'] / 100 : 0;
        if ($taxAmount > 0) {
          // Create a tax item
          $taxItem = new \WC_Order_Item_Tax();
          $taxItem->set_rate_code($tax['name'] ?? 'Square Tax');
          $taxItem->set_tax_total($taxAmount);
          $taxItem->set_label($tax['name'] ?? 'Tax');
          $order->add_item($taxItem);
        }
      }
    }

    // Handle Discounts
    if (isset($squareOrder['discounts']) && !empty($squareOrder['discounts'])) {
      foreach ($squareOrder['discounts'] as $discount) {
        $discountAmount = isset($discount['applied_money']['amount']) ? $discount['applied_money']['amount'] / 100 : 0;
        if ($discountAmount > 0) {
          // Apply discount as a negative fee
          $order->add_fee(new \WC_Order_Item_Fee([
            'name' => $discount['name'] ?? __('Discount', 'squarewoosync'),
            'amount' => -$discountAmount, // Negative for discounts
            'total' => -$discountAmount,
            'taxable' => false,
          ]));
        }
      }
    }

    // Set the cart tax using the public method
    $totalTaxAmount = isset($squareOrder['total_tax_money']['amount']) ? $squareOrder['total_tax_money']['amount'] / 100 : 0;
    if ($totalTaxAmount > 0) {
      $order->set_cart_tax($totalTaxAmount);
    }
  }

  private function set_order_status($order, $squareOrder)
  {
    $squareOrderState = isset($squareOrder['state']) ? $squareOrder['state'] : null;

    // Determine WooCommerce order status based on Square order state
    $newOrderStatus = 'processing'; // Default to 'processing'

    switch ($squareOrderState) {
      case 'CANCELED':
        $newOrderStatus = 'cancelled';
        break;
      case 'PROPOSED':
        $newOrderStatus = 'pending'; // Changed from 'draft' to 'pending'
        break;
      case 'COMPLETED':
        $newOrderStatus = 'completed';
        break;
      case 'OPEN':
        $newOrderStatus = 'processing';
        break;
      default:
        $newOrderStatus = 'processing';
        break;
    }

    // Update the WooCommerce order status if different
    if ($order->get_status() !== $newOrderStatus) {
      $order->update_status($newOrderStatus, __('Order status updated based on Square order state and payment status.', 'squarewoosync'));
      $order->add_order_note(sprintf(__('Order status set to %s based on Square state: %s', 'squarewoosync'), $newOrderStatus, $squareOrderState));
    }

    // Ensure the order is saved
    $order->save();
  }

  private function handle_fulfillments($order, $squareOrder)
  {
    if (isset($squareOrder['fulfillments']) && is_array($squareOrder['fulfillments'])) {
      foreach ($squareOrder['fulfillments'] as $fulfillment) {
        $fulfillmentType = $fulfillment['type'] ?? null;

        switch ($fulfillmentType) {
          case 'PICKUP':
            $pickupMethod = $this->settings['orders']['pickupMethod'] ?? null;
            if ($pickupMethod) {
              $this->set_pickup_shipping_method($order, $pickupMethod, $fulfillment);
            }
            break;

          case 'SHIPMENT':
          case 'DELIVERY':
            $this->set_custom_shipping_line($order, $fulfillment);
            break;

          default:
            // Handle unsupported fulfillment types if needed
            error_log("Unsupported fulfillment type: " . $fulfillmentType);
            break;
        }
      }
    }
  }

  private function set_custom_shipping_line($order, $fulfillment)
  {
    // Remove existing shipping items
    foreach ($order->get_items('shipping') as $item_id => $item) {
      $order->remove_item($item_id);
    }

    // Create a new shipping item
    $shipping_item = new \WC_Order_Item_Shipping();
    $shipping_item->set_method_title(__('Square Shipping', 'squarewoosync')); // Name of the shipping method
    $shipping_item->set_method_id('custom_shipping'); // A custom ID
    $shipping_item->set_total(0); // Set shipping cost, update if necessary

    // Add fulfillment details as meta data
    $shipmentDetails = $fulfillment['shipment_details'] ?? [];
    if (!empty($shipmentDetails)) {
      $shippingItemAddress = $shipmentDetails['recipient']['address'] ?? null;
      if ($shippingItemAddress) {
        $shipping_item->add_meta_data('Shipping Address', json_encode($shippingItemAddress), true);
      }

      $trackingNumber = $shipmentDetails['tracking_number'] ?? '';
      if (!empty($trackingNumber)) {
        $shipping_item->add_meta_data('Tracking Number', $trackingNumber, true);
      }

      $carrier = $shipmentDetails['carrier'] ?? '';
      if (!empty($carrier)) {
        $shipping_item->add_meta_data('Carrier', $carrier, true);
      }
    }

    // Add the shipping item to the order
    $order->add_item($shipping_item);

    // Save the order
    $order->save();
  }

  private function set_pickup_shipping_method($order, $pickupMethod, $fulfillment)
  {
    // Remove existing shipping items
    foreach ($order->get_items('shipping') as $item_id => $item) {
      $order->remove_item($item_id);
    }

    // Fetch the WooCommerce shipping method instance by ID
    $shipping_methods = WC()->shipping->get_shipping_methods();
    $shipping_method = isset($shipping_methods[$pickupMethod]) ? $shipping_methods[$pickupMethod] : null;

    if (!$shipping_method) {
      throw new \Exception(sprintf(__('Shipping method with ID %s not found.', 'squarewoosync'), $pickupMethod));
    }

    // Create a new shipping item
    $shipping_item = new \WC_Order_Item_Shipping();
    $shipping_item->set_method_title($shipping_method->get_method_title());
    $shipping_item->set_method_id($pickupMethod);
    $shipping_item->set_total(0); // Assuming pickup is free or explicitly set to 0

    // Add any fulfillment details as meta data
    $pickupDetails = isset($fulfillment['pickup_details']) ? $fulfillment['pickup_details'] : [];

    if (!empty($pickupDetails)) {
      $pickupAt = isset($pickupDetails['pickup_at']) ? $pickupDetails['pickup_at'] : '';
      $placedAt = isset($pickupDetails['placed_at']) ? $pickupDetails['placed_at'] : '';
      $recipient = isset($pickupDetails['recipient']) ? $pickupDetails['recipient'] : [];

      $shipping_item->add_meta_data('Pickup At', $pickupAt, true);
      $shipping_item->add_meta_data('Placed At', $placedAt, true);
      if (!empty($recipient)) {
        $shipping_item->add_meta_data('Recipient', $recipient['display_name'], true);
      }
    }

    // Add the shipping item to the order
    $order->add_item($shipping_item);

    // Save the changes to the order
    $order->save();
  }

  private function set_addresses($order, $squareOrder, $squareCustomerData = null)
  {
    $shippingAddress = isset($squareOrder['shipping_address']) ? $squareOrder['shipping_address'] : null;
    $billingAddress  = isset($squareOrder['billing_address']) ? $squareOrder['billing_address'] : null;

    // If billing or shipping address is not set in the order, use the Square customer data
    if (!$billingAddress && $squareCustomerData && isset($squareCustomerData['address'])) {
      $billingAddress = $squareCustomerData['address'];
      $billingAddress['first_name'] = $squareCustomerData['given_name'] ?? '';
      $billingAddress['last_name'] = $squareCustomerData['family_name'] ?? '';
      $billingAddress['email'] = $squareCustomerData['email_address'] ?? '';
      $billingAddress['phone'] = $squareCustomerData['phone_number'] ?? '';
    }

    if (!$shippingAddress && $squareCustomerData && isset($squareCustomerData['address'])) {
      $shippingAddress = $squareCustomerData['address'];
      $shippingAddress['first_name'] = $squareCustomerData['given_name'] ?? '';
      $shippingAddress['last_name'] = $squareCustomerData['family_name'] ?? '';
      $shippingAddress['email'] = $squareCustomerData['email_address'] ?? '';
      $shippingAddress['phone'] = $squareCustomerData['phone_number'] ?? '';
    }

    if ($billingAddress) {
      $order->set_billing_first_name($billingAddress['first_name'] ?? '');
      $order->set_billing_last_name($billingAddress['last_name'] ?? '');
      $order->set_billing_address_1($billingAddress['address_line_1'] ?? '');
      $order->set_billing_address_2($billingAddress['address_line_2'] ?? '');
      $order->set_billing_city($billingAddress['locality'] ?? '');
      $order->set_billing_state($billingAddress['administrative_district_level_1'] ?? '');
      $order->set_billing_postcode($billingAddress['postal_code'] ?? '');
      $order->set_billing_country($billingAddress['country'] ?? '');
      $order->set_billing_email($billingAddress['email'] ?? '');
      $order->set_billing_phone($billingAddress['phone'] ?? '');
    }

    if ($shippingAddress) {
      $order->set_shipping_first_name($shippingAddress['first_name'] ?? '');
      $order->set_shipping_last_name($shippingAddress['last_name'] ?? '');
      $order->set_shipping_address_1($shippingAddress['address_line_1'] ?? '');
      $order->set_shipping_address_2($shippingAddress['address_line_2'] ?? '');
      $order->set_shipping_city($shippingAddress['locality'] ?? '');
      $order->set_shipping_state($shippingAddress['administrative_district_level_1'] ?? '');
      $order->set_shipping_postcode($shippingAddress['postal_code'] ?? '');
      $order->set_shipping_country($shippingAddress['country'] ?? '');
      $order->set_shipping_phone($shippingAddress['phone'] ?? '');
    }
  }
}
