<?php

namespace Pixeldev\SquareWooSync\Square;

use Pixeldev\SquareWooSync\Square\SquareHelper;
use Pixeldev\SquareWooSync\Woo\CreateProduct;

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

/**
 * Class responsible for importing products from Square to WooCommerce.
 */
class SquareImport extends SquareHelper
{

  /**
   * Constructor.
   */
  public function __construct()
  {
    parent::__construct();

    add_action('sws_import_chunk', [$this, 'handle_import_cron'], 10, 3);
  }
  /**
   * Imports products from Square to WooCommerce.
   *
   * @param array $square_products Products to import.
   * @param array $data_to_import Data to be imported.
   * @param bool $update_only Flag to update existing products only.
   * @return array Results of the import process.
   */
  public function import_products($square_products, $data_to_import, $update_only = false)
  {
    global $wpdb;
    $results = [];
    $table_name = $wpdb->prefix . 'square_inventory';

    $modifiers = [];
    if (isset($data_to_import['modifiers']) && $data_to_import['modifiers'] === true) {
      $square = new SquareHelper();
      $modifiersResponse = $square->square_api_request('/catalog/list?types=MODIFIER_LIST');

      if (isset($modifiersResponse['success']) && $modifiersResponse['success'] === true) {
        if (isset($modifiersResponse['data']['objects'])) {
          $modifiers = $modifiersResponse['data']['objects'];
        }
      }
    }


    foreach ($square_products as $square_product) {

      try {
        $settings = get_option('square-woo-sync_settings', []);

        if (isset($square_product['created_at'])) {
          $created_at = new \DateTime($square_product['created_at']);
          $is_recent = $created_at >= (new \DateTime())->modify('-15 minutes');

          if (!isset($settings['wooAuto']['autoWooCreation']) || $settings['wooAuto']['autoWooCreation'] === false) {
            $is_recent = false;
          }

          // Check if the main product or any variations were created recently
          if ($is_recent || (isset($square_product['item_data']['variations']) && is_array($square_product['item_data']['variations']))) {
            foreach ($square_product['item_data']['variations'] as $variation) {
              if (isset($variation['created_at'])) {
                $variation_created_at = new \DateTime($variation['created_at']);
                $variation_is_recent = $variation_created_at >= (new \DateTime())->modify('-15 minutes');

                if ($variation_is_recent) {
                  if (isset($settings['wooAuto']['autoWooCreation']) && $settings['wooAuto']['autoWooCreation'] === true) {
                    $is_recent = true; // Mark the product as recent if any variation is recent
                  }
                  break;
                }
              }
            }
          }



          if ($is_recent && isset($settings['wooAuto']['autoWooCreation']) && $settings['wooAuto']['autoWooCreation'] === true) {
            $update_only = false;

            // Set update_only based on additional conditions
            if (
              isset($square_product['item_data']['visibility']) && $square_product['item_data']['visibility'] === 'PRIVATE' &&
              isset($settings['wooAuto']['ecomOnly']) && $settings['wooAuto']['ecomOnly'] === true
            ) {
              $update_only = true;
            }
          }
        }



        $create_product = new CreateProduct();
        $existing_products = $create_product->get_product_by_square_id($square_product['id']);


        $product_variation_ids = [];
        $matching_product = null;

        if ($existing_products) {
          foreach ($existing_products as $product) {
            $variation_id = $product->get_meta('square_variation_id', true);
            if ($variation_id) {
              $product_variation_ids[$variation_id] = $product; // Store variation ID as key and product as value for easy lookup
            }
          }
        }

        if ($product_variation_ids) {
          foreach ($square_product['item_data']['variations'] as $variation) {
            if (isset($product_variation_ids[$variation['id']])) {
              $matching_product = $product_variation_ids[$variation['id']];
              break;
            }
          }
        }



        if (!$product_variation_ids && !empty($existing_products)) {
          $matching_product = $existing_products[0];
        }



        $wc_product_data = $this->map_square_product_to_woocommerce($square_product, $matching_product, $update_only, $modifiers);

        $product_id = $create_product->create_or_update_product($wc_product_data, $data_to_import, $update_only, $matching_product);


        // Validation Step: Check Essential Data Points
        if (!$this->is_product_valid($product_id)) {
          // Delete the invalid product
          wp_delete_post($product_id, true); // 'true' for force delete
          $results[] = [
            'status' => 'deleted',
            'product_id' => $product_id,
            'square_id' => $square_product['id'],
            'message' => esc_html__('Deleted invalid product: ', 'squarewoosync') . esc_html($product_id)
          ];
          continue; // Skip further processing for this product
        }

        $existing_row = $wpdb->get_row($wpdb->prepare(
          "SELECT * FROM $table_name WHERE product_id = %s",
          $square_product['id']
        ), ARRAY_A);


        $decoded_data = [];

        if (isset($existing_product['product_data'])) {
          $decoded_data = json_decode($existing_row['product_data'], true);
        }


        if (!is_array($product_id)) {
          $product = wc_get_product($product_id);
          if ($product) {
            $name = $product->get_name();
            $result_entry = [
              'status' => 'success',
              'product_id' => $product_id,
              'square_id' => $square_product['id'],
              'message' => esc_html__('Successfully synced: ', 'squarewoosync') . esc_html($name) . esc_html__(' from Square to Woo', 'squarewoosync')
            ];

            // Initialize the variations array
            $variation_ids = [];

            // Check if the product is a variable product and handle its variations
            if ($product->is_type('variable')) {
              $variations = $product->get_children();
              foreach ($variations as $variation_id) {
                $variation_square_product_id = get_post_meta($variation_id, 'square_product_id', true);
                if ($variation_square_product_id) {
                  $variation_ids[] = ['variation_id' => $variation_id, 'square_product_id' => $variation_square_product_id];

                  if (isset($decoded_data['item_data'])) {
                    foreach ($decoded_data['item_data']['variations'] as &$variation) {
                      if ($variation['id'] === $variation_square_product_id) {
                        $variation['imported'] = true; // Set imported to true for the current variation
                        $variation['woocommerce_product_id'] = $variation_id; // Optionally, add the WooCommerce variation ID
                      }
                    }
                  }

                  unset($variation); // Break the reference with the last element
                }
              }
            }

            // Check if the product is a simple product and has the square_variation_id meta data
            if ($product->is_type('simple')) {
              $square_variation_id = get_post_meta($product->get_id(), 'square_variation_id', true);
              if ($square_variation_id) {
                $variation_ids[] = ['variation_id' => $product->get_id(), 'square_product_id' => $square_variation_id];
              }

              if (isset($decoded_data['item_data']['variations'])) {
                foreach ($decoded_data['item_data']['variations'] as &$variation) {
                  if ($variation['id'] === $square_variation_id) {
                    $variation['imported'] = true;
                    $variation['woocommerce_product_id'] = $product->get_id();
                  }
                }
              }
              unset($variation); // Break the reference with the last element
            }

            // Add variations to the result entry if there are any
            if (!empty($variation_ids)) {
              $result_entry['variations'] = $variation_ids;
            }

            $results[] = $result_entry;

            // Set the imported status and WooCommerce product ID
            $decoded_data['imported'] = true;
            $decoded_data['woocommerce_product_id'] = $product_id;

            // Serialize the updated data
            if (isset($existing_product['product_data']['item_data'])) {
              $updated_data_serialized = json_encode($decoded_data);

              // Update the existing row in the database
              $update_result = $wpdb->update(
                $table_name,
                array(
                  'product_data' => $updated_data_serialized
                ),
                array('product_id' => $square_product['id']),
                array('%s'),
                array('%s')
              );

              // Log the result of the update operation
              if ($update_result === false) {
                error_log('Failed to update row for product_id: ' . $square_product['id']);
              }
            }
          }
        } else {
          $results[] = $product_id;
        }
      } catch (\Exception $e) {
        error_log('Error importing product: ' . $e->getMessage());
        $results[] = ['status' => 'failure', 'product_id' => null, 'message' => 'Exception occurred: ' . $e->getMessage()];
      }
    }

    return $results;
  }


  /**
   * Validate the WooCommerce product to ensure it has essential data.
   *
   * @param int $product_id The ID of the WooCommerce product.
   * @return bool True if valid, False otherwise.
   */
  private function is_product_valid($product_id)
  {
    $product = wc_get_product($product_id);

    if (!$product) {
      return false;
    }

    // Check Title
    $title = $product->get_name();
    if (strtolower($title) === 'product') {
      return false;
    }

    // Initialize a flag to track if at least one data point is set
    $has_essential_data = false;

    // Check Title is not empty
    if (!empty($title)) {
      $has_essential_data = true;
    }

    // Check Price
    $price = $product->get_price();
    if (!empty($price)) {
      $has_essential_data = true;
    }

    // Check Stock Status
    if ($product->managing_stock()) {
      $stock_quantity = $product->get_stock_quantity();
      if (!is_null($stock_quantity)) { // Allow stock quantity to be zero but not null
        $has_essential_data = true;
      }
    } else {
      // If not managing stock, consider it as having essential data
      $has_essential_data = true;
    }

    // Check Image
    $image_id = $product->get_image_id();
    if (!empty($image_id)) {
      $has_essential_data = true;
    }

    // Check Description
    $description = $product->get_description();
    if (!empty($description)) {
      $has_essential_data = true;
    }

    // Check Category
    $categories = wp_get_post_terms($product_id, 'product_cat');
    if (!empty($categories) && !is_wp_error($categories)) {
      $has_essential_data = true;
    }

    // If no essential data points are set, the product is invalid
    if (!$has_essential_data) {
      return false;
    }

    // If title is not 'Product' and at least one data point is set, the product is valid
    return true;
  }

  /**
   * Maps a Square product to a WooCommerce product format.
   *
   * @param array  $square_product  The Square product to map.
   * @param object $existing_product An existing WC Product object if any.
   * @param bool   $update_only     Whether we are update-only mode or can create new products.
   * @param array  $modifiers       The array of all Square modifier_list objects (optional).
   *
   * @return array The WooCommerce product data.
   */
  public function map_square_product_to_woocommerce($square_product, $existing_product, $update_only, $modifiers = [])
  {
    $wc_product_data = [];

    $zero_decimal_currencies = [
      'BIF',
      'CLP',
      'DJF',
      'GNF',
      'JPY',
      'KMF',
      'KRW',
      'MGA',
      'PYG',
      'RWF',
      'UGX',
      'VND',
      'VUV',
      'XAF',
      'XOF',
      'XPF'
    ];

    if (!empty($square_product['present_at_location_ids'])) {
      $wc_product_data['locations'] =  $square_product['present_at_location_ids'];
    }


    // Proceed with the existing product data

    // Map basic product details from Square to WooCommerce
    $wc_product_data['name'] = $square_product['item_data']['name'];
    $wc_product_data['description'] = $square_product['item_data']['description'] ?? '';


    // Handle product type and variations
    if (isset($square_product['variable']) && $square_product['variable'] === true) {
      if ($existing_product && $existing_product->get_type() === 'variable') {
        $wc_product_data['type'] = 'variable';
      } else {
        if (isset($square_product['item_data']['variations']) && is_array($square_product['item_data']['variations']) && count($square_product['item_data']['variations']) === 1) {
          $wc_product_data['type'] = 'simple';
          $wc_product_data['variation_id'] = $square_product['item_data']['variations'][0]['id'];
        } else {
          if ($update_only && $existing_product) {
            $wc_product_data['type'] = $existing_product->get_type();
          } else {
            $wc_product_data['type'] = 'variable';
          }
        }
      }
    } else {
      if ($existing_product && $existing_product->get_type() === 'variable') {
        $wc_product_data['type'] = 'variable';
      } else {
        if (isset($square_product['item_data']['variations']) && is_array($square_product['item_data']['variations']) && count($square_product['item_data']['variations']) > 1) {
          if ($update_only && $existing_product) {
            $wc_product_data['type'] = $existing_product->get_type();
          } else {
            $wc_product_data['type'] = 'variable';
          }
        } else {
          if ($update_only && $existing_product) {
            $wc_product_data['type'] = $existing_product->get_type();
          } else {
            $wc_product_data['type'] = 'simple';
          }
        }
      }
    }

    if ($existing_product) {

      $square_variation_id = get_post_meta($existing_product->get_id(), 'square_variation_id', true);
      if ($square_variation_id) {
        // Iterate through the variations to find the matching square_variation_id
        foreach ($square_product['item_data']['variations'] as $variation) {
          if ($variation['id'] === $square_variation_id) {
            $wc_product_data['sku'] = $variation['item_variation_data']['sku'];
            $wc_product_data['upc'] = isset($variation['item_variation_data']['upc']) ? $variation['item_variation_data']['upc'] : '';
            $wc_product_data['stock'] = intval($variation['inventory_count'] ?? '0');


            // Sanity check that price_money exists:
            if (!empty($variation['item_variation_data']['price_money'])) {
              $price_money = $variation['item_variation_data']['price_money'];
              $amount = $price_money['amount'];
              $currency = $price_money['currency'];

              // Step 2 & 3: Check if currency is zero-decimal
              if (in_array($currency, $zero_decimal_currencies, true)) {
                $wc_product_data['price'] = $variation['item_variation_data']['price_money']['amount'];
              } else {
                $wc_product_data['price'] = $variation['item_variation_data']['price_money']['amount'] / 100;
              }
            } else {
              $wc_product_data['price'] = $variation['item_variation_data']['price_money']['amount'] / 100;
            }

            break;
          }
        }
      } else {
        // Use the data from the first variation if no square_variation_id is found
        $wc_product_data['sku'] = $square_product['item_data']['variations'][0]['item_variation_data']['sku'];
        $variationData = $square_product['item_data']['variations'][0]['item_variation_data'] ?? [];
        $wc_product_data['upc'] = $variationData['upc'] ?? '';

        $wc_product_data['stock'] = intval($square_product['item_data']['variations'][0]['inventory_count'] ?? '0');




        // Sanity check that price_money exists:
        if (!empty($square_product['item_data']['variations'][0]['item_variation_data']['price_money'])) {
          $price_money = $square_product['item_data']['variations'][0]['item_variation_data']['price_money'];
          $currency = $price_money['currency'];

          // Step 2 & 3: Check if currency is zero-decimal
          if (in_array($currency, $zero_decimal_currencies, true)) {
            $wc_product_data['price'] = $square_product['item_data']['variations'][0]['item_variation_data']['price_money']['amount'];
          } else {
            $wc_product_data['price'] = $square_product['item_data']['variations'][0]['item_variation_data']['price_money']['amount'] / 100;
          }
        } else {
          $wc_product_data['price'] = $square_product['item_data']['variations'][0]['item_variation_data']['price_money']['amount'] / 100;
        }
      }
    }


    $wc_product_data['square_product_id'] = $square_product['id'];

    // Handle categories
    $categories = $square_product['item_data']['categories'] ?? [];
    $wc_product_data['categories'] = $categories;

    // override if the “reporting” import type is selected and data exists
    $settings = get_option('square-woo-sync_settings', []);
    if (
      isset($settings['importCategoryType']) &&
      $settings['importCategoryType'] === 'reporting' &&
      ! empty($square_product['item_data']['reporting_category'])
    ) {
      $wc_product_data['categories'] = [
        $square_product['item_data']['reporting_category']
      ];
    }


    // Map variations if the product has variations
    $wc_product_data['variations'] = [];
    foreach ($square_product['item_data']['variations'] as $variation) {

      $amount = 0;
      $currency = 'USD';

      // Sanity check that price_money exists:
      if (!empty($variation['item_variation_data']['price_money'])) {
        $price_money = $variation['item_variation_data']['price_money'];
        $amount = $price_money['amount'];
        $currency = $price_money['currency'];

        // Step 2 & 3: Check if currency is zero-decimal
        if (!in_array($currency, $zero_decimal_currencies, true)) {
          // Non-zero-decimal currency => divide by 100
          $amount /= 100;
        }
      }

      $variation_data = [
        'name' => $variation['item_variation_data']['name'] ?? '',
        'sku' => $variation['item_variation_data']['sku'] ?? '',
        'price'              => $amount,
        'attributes' => [],
        'variation_square_id' => $variation['id'],
        'currency'           => $currency,
        'stock' => isset($variation['inventory_count']) ? intval($variation['inventory_count']) : 0,
        'image_ids' => $variation['item_variation_data']['image_ids'] ?? [],
        'track_inventory' => $variation['item_variation_data']['track_inventory'] ?? true,
        'location_overrides' => $variation['item_variation_data']['location_overrides'] ?? []
      ];

      // Handle attributes for variations
      if (isset($variation['item_variation_data']['item_option_values'])) {
        foreach ($variation['item_variation_data']['item_option_values'] as $option) {
          $variation_data['attributes'][] = [
            'name' => $option['option_name'],
            'option' => $option['option_value']
          ];
        }
      }

      $wc_product_data['variations'][] = $variation_data;
    }


    // Handle image URLs
    if (!empty($square_product['item_data']['images'])) {
      $wc_product_data['images'] = $square_product['item_data']['images'];
    }

    // -------------------------------
    // 1) Map Square modifiers to WC
    // -------------------------------
    $wc_product_data['modifiers'] = [];


    if (!empty($square_product['item_data']['modifier_list_info']) && is_array($square_product['item_data']['modifier_list_info'])) {

      foreach ($square_product['item_data']['modifier_list_info'] as $ml_info) {
        $modifier_list_id = $ml_info['modifier_list_id'] ?? '';
        if (!$modifier_list_id) {
          continue;
        }

        // Find the matching modifier list in the $modifiers array
        foreach ($modifiers as $modifier_list) {
          if (!empty($modifier_list['id']) && $modifier_list['id'] === $modifier_list_id) {

            // Prepare an array to hold each sub-modifier
            $sub_modifiers = [];
            if (!empty($modifier_list['modifier_list_data']['modifiers'])) {
              foreach ($modifier_list['modifier_list_data']['modifiers'] as $m) {
                // Make sure 'modifier_data' is set
                if (empty($m['modifier_data'])) {
                  continue;
                }

                // Price logic
                $sub_price   = $m['modifier_data']['price_money']['amount'] ?? 0;
                $sub_currency = $m['modifier_data']['price_money']['currency'] ?? 'USD';

                // Adjust if not zero-decimal
                if (!in_array($sub_currency, $zero_decimal_currencies, true)) {
                  $sub_price /= 100.0;
                }

                $sub_modifiers[] = [
                  'id'       => $m['id'],
                  'name'     => $m['modifier_data']['name'],
                  'price'    => $sub_price,
                  'currency' => $sub_currency,
                  'location_overrides' => $m['modifier_data']['location_overrides'] ?? []
                ];
              }
            }

            // Build the final structure for this list
            $wc_product_data['modifiers'][] = [
              'modifier_list_id'  => $modifier_list['id'],
              'name'              => $modifier_list['modifier_list_data']['name'] ?? '',
              'selection_type'    => $modifier_list['modifier_list_data']['selection_type'] ?? '',
              'enabled'           => $ml_info['enabled'] ?? true,
              // You can also capture min/max if needed:
              'min_selected_modifiers' => $ml_info['min_selected_modifiers'] ?? 0,
              'max_selected_modifiers' => $ml_info['max_selected_modifiers'] ?? 0,
              // And the array of sub-modifiers:
              'modifiers'         => $sub_modifiers,
            ];

            // Break once you match, assuming only one unique ID
            break;
          }
        }
      }
    }
    // -------------------------------
    // End of Modifiers mapping
    // -------------------------------

    return $wc_product_data;
  }


  /**
   * Action Scheduler callback for processing one chunk of product items.
   *
   * @param array $productItems  Each item is [ 'parent_id'=>'...', 'selected_variations'=>[...] ]
   * @param array $dataToImport  The data to import (like [ 'title'=>true, 'price'=>true, ... ])
   * @param int   $chunkIndex    The chunk index (optional).
   */
  public function handle_import_cron($productItems, $dataToImport, $chunkIndex = 0)
  {
    $settings = get_option('square-woo-sync_settings', []);
    $inv = $settings['inventory'] ?? [];

    // If import was canceled or never started, skip
    if (empty($inv['isImporting']) || $inv['isImporting'] === false) {
      return;
    }

    // If we want to ensure each chunk only runs once, track processedChunks
    if (!isset($inv['importProgress']['processedChunks'])) {
      $inv['importProgress']['processedChunks'] = [];
    }
    if (in_array($chunkIndex, $inv['importProgress']['processedChunks'], true)) {
      // This chunk was already processed => skip to avoid duplicates
      return;
    }

    // De-duplicate any repeated parent_id within the same chunk
    $unique = [];
    foreach ($productItems as $item) {
      $unique[$item['parent_id']] = $item;
    }
    $productItems = array_values($unique);

    // Reconstruct the full product data from DB
    $reconstructed = $this->reconstruct_chunk_products($productItems);

    // If nothing could be reconstructed => record an error
    if (empty($reconstructed)) {
      $this->record_import_error($settings, 'No products could be reconstructed for this chunk.');
      return;
    }

    // Attempt the actual import using import_products (unchanged)
    try {
      $result = $this->import_products($reconstructed, $dataToImport);
    } catch (\Exception $e) {
      $this->record_import_error($settings, 'Chunk import exception: ' . $e->getMessage());
      return;
    }

    // If we didn't get an array => record an error
    if (! is_array($result)) {
      $this->record_import_error($settings, 'import_products() did not return an array.');
      return;
    }

    // Update the master results (the "progress" array)
    if (!isset($inv['importProgress']) || !is_array($inv['importProgress'])) {
      $inv['importProgress'] = [];
    }
    if (!isset($inv['importProgress']['results']) || !is_array($inv['importProgress']['results'])) {
      $inv['importProgress']['results'] = [];
    }

    // Append the results from import_products
    foreach ($result as $row) {
      $inv['importProgress']['results'][] = $row;
    }

    // "processed" is how many parent items we handled in this chunk
    $processedCount = count($productItems);
    $inv['importProgress']['processed'] += $processedCount;

    // Mark this chunkIndex as processed to avoid re-running
    $inv['importProgress']['processedChunks'][] = $chunkIndex;

    // Check if we've processed everything
    if ($inv['importProgress']['processed'] >= $inv['importProgress']['total']) {
      $inv['isImporting'] = false;
      $inv['importProgress']['finished'] = true;
      $inv['importProgress']['finished_at'] = current_time('mysql');
    }

    // Save the updated progress
    $settings['inventory'] = $inv;
    update_option('square-woo-sync_settings', $settings);
  }


  /**
   * Reconstructs product data from DB using minimal data: [ 'parent_id'=>'...', 'selected_variations'=>[] ].
   */
  public function reconstruct_chunk_products(array $productItems): array
  {
    global $wpdb;
    $table_name = $wpdb->prefix . 'square_inventory';

    $fullList = [];

    foreach ($productItems as $item) {
      $parentId = $item['parent_id'] ?? '';
      if (!$parentId) {
        continue;
      }

      // 1) Fetch the product_data JSON from DB
      $row = $wpdb->get_row(
        $wpdb->prepare("SELECT product_data FROM {$table_name} WHERE product_id = %s", $parentId),
        ARRAY_A
      );
      if (!$row) {
        continue;
      }

      // 2) Decode JSON
      $decoded = json_decode($row['product_data'], true);
      if (!$decoded || json_last_error() !== JSON_ERROR_NONE) {
        continue;
      }

      // 3) If subRows => filter variations
      $variationIds = $item['selected_variations'] ?? [];
      if (!empty($variationIds) && !empty($decoded['item_data']['variations'])) {
        $decoded['item_data']['variations'] = array_values(array_filter(
          $decoded['item_data']['variations'],
          function ($var) use ($variationIds) {
            return !empty($var['id']) && in_array($var['id'], $variationIds, true);
          }
        ));
      }

      $fullList[] = $decoded;
    }

    return $fullList;
  }

  /**
   * Called when an error occurs during chunk processing (e.g. empty result, exception).
   * This updates plugin settings, sets isImporting=false, records the error, and finishes the import.
   */
  public function record_import_error(array $allSettings, string $errorMsg): void
  {
    $inv = $allSettings['inventory'] ?? [];

    $inv['isImporting'] = false;
    if (!isset($inv['importProgress']) || !is_array($inv['importProgress'])) {
      $inv['importProgress'] = [];
    }
    $inv['importProgress']['finished'] = true;
    $inv['importProgress']['finished_at'] = current_time('mysql');
    $inv['importProgress']['error'] = $errorMsg;

    if (!isset($inv['importProgress']['results']) || !is_array($inv['importProgress']['results'])) {
      $inv['importProgress']['results'] = [];
    }
    $inv['importProgress']['results'][] = [
      'status'  => 'failed',
      'message' => $errorMsg,
    ];

    $allSettings['inventory'] = $inv;
    update_option('square-woo-sync_settings', $allSettings);
  }
}
