<?php
/**
 * Category Sync Handler
 *
 * @package FKWCSQ\Sync
 */

namespace FKWCSQ\Includes\Sync;

use FKWCSQ\Includes\Traits\Instance;
use function get_term_by;
use function is_wp_error;
use function update_term_meta;
use function wp_update_term;
use function wp_insert_term;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Handles category synchronization between WooCommerce and Square
 */
class Category {
	use Instance;

	/**
	 *
	 * Square API instance
	 *
	 * @var \FKWCSQ\Includes\API
	 */
	private $api;

	/**
	 * Constructor
	 */
	private function __construct() {
		$this->api = \FKWCSQ\Includes\API::get_instance();
	}

	/**
	 * Sync category from WooCommerce to Square
	 *
	 * @param int $term_id WooCommerce category ID
	 * @return bool Success status
	 * @throws \Exception When syncing with Square API fails
	 */
	public function sync_category_to_square( $term_id ) {
		try {
			$term = get_term( $term_id, 'product_cat' );

			if ( ! $term || is_wp_error( $term ) ) {
				return false;
			}

			$square_id     = get_term_meta( $term_id, '_square_id', true );
			$category_data = array(
				'name'        => $term->name,
				'description' => $term->description,
			);

			if ( $square_id ) {
				$response = $this->api->update_category( $square_id, $category_data );
			} else {
				$response = $this->api->create_category( $category_data );
				if ( ! is_wp_error( $response ) && isset( $response['id'] ) ) {
					update_term_meta( $term_id, '_square_id', $response['id'] );
				}
			}
			if ( is_wp_error( $response ) ) {
				throw new \Exception( $response->get_error_message() );
			}

			do_action( 'fkwcsq_category_synced_to_square', $term_id, $response );
			return true;
		} catch ( \Exception $e ) {
			return false;
		}
	}

	/**
	 * Sync category from Square to WooCommerce
	 *
	 * @param array $square_data Square category data
	 * @return bool Success status
	 */
	public function sync_category_from_square( $square_data ) {
		try {
			$term_id   = $this->find_category_by_square_id( $square_data['id'] );
			$term_data = array(
				'name'        => $square_data['name'],
				'description' => $square_data['description'] ?? '',
			);

			if ( $term_id ) {
				wp_update_term( $term_id, 'product_cat', $term_data );
			} else {
				$term = wp_insert_term( $term_data['name'], 'product_cat', $term_data );
				if ( is_wp_error( $term ) ) {
					return false;
				}
				update_term_meta( $term['term_id'], '_square_id', $square_data['id'] );
			}

			do_action( 'fkwcsq_category_synced_from_square', $term_id, $square_data );
			return true;
		} catch ( \Exception $e ) {
			return false;
		}
	}

	/**
	 * Delete category from Square
	 *
	 * @param int    $term_id      Term ID
	 * @param string $taxonomy     Taxonomy name
	 * @return bool Success status
	 * @throws \Exception When syncing with Square API fails
	 */
	public function delete_category_from_square( $term_id, $taxonomy ) {

		// Only proceed if this is a product category
		if ( 'product_cat' !== $taxonomy ) {
			return false;
		}

		try {
			// Get Square ID from term meta
			$square_id = get_term_meta( $term_id, '_square_id', true );

			if ( ! $square_id ) {
				return false;
			}

			$response = $this->api->delete_category( $square_id );

			if ( is_wp_error( $response ) ) {
				throw new \Exception( $response->get_error_message() );
			}

			delete_term_meta( $term_id, '_square_id' );

			do_action( 'fkwcsq_category_deleted_from_square_' . $term_id );
			return true;

		} catch ( \Exception $e ) {
			return false;
		}
	}

	/**
	 * Find WooCommerce category by Square ID
	 *
	 * @param string $square_id Square category ID
	 *
	 * @return int|false Term ID or false if not found
	 */
	private function find_category_by_square_id( $square_id ) {
		$args = array(
			'taxonomy'   => 'product_cat',
			'meta_key'   => '_square_id', //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Necessary for Square integration lookup
			'meta_value' => $square_id, //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Necessary for Square integration lookup
			'fields'     => 'ids',
			'number'     => 1,
		);

		$terms = get_terms( $args );

		return ! is_wp_error( $terms ) && ! empty( $terms ) ? $terms[0] : false;
	}
	/**
	 * Schedule batch sync of all categories
	 *
	 * @return array Summary of sync results
	 */
	public function schedule_batch_sync() {
		try {
			$total_categories = 0;
			$success_count    = 0;
			$failed_count     = 0;
			$success_ids      = array();
			$failed_ids       = array();
			$errors           = array();

			// Get all product category terms
			$categories = get_terms(
				array(
					'taxonomy'   => 'product_cat',
					'hide_empty' => false,
				)
			);

			$total_categories = is_array( $categories ) ? count( $categories ) : 0;

			if ( empty( $categories ) || is_wp_error( $categories ) ) {
				return array(
					'total'       => 0,
					'success'     => 0,
					'failed'      => 0,
					'success_ids' => array(),
					'failed_ids'  => array(),
					'errors'      => array(),
				);
			}

			// Process all categories immediately
			foreach ( $categories as $category ) {
				try {
					if ( $this->sync_category_to_square( $category->term_id ) ) {
						++$success_count;
						$success_ids[] = $category->term_id;
					} else {
						++$failed_count;
						$failed_ids[] = $category->term_id;
						$errors[]     = sprintf( 'Category %s (ID: %d): sync failed', $category->name, $category->term_id );
					}
				} catch ( \Exception $e ) {
					++$failed_count;
					$failed_ids[] = $category->term_id;
					$errors[]     = sprintf( 'Category %s (ID: %d): %s', $category->name, $category->term_id, $e->getMessage() );
				}
			}

			return array(
				'total'       => $total_categories,
				'success'     => $success_count,
				'failed'      => $failed_count,
				'success_ids' => $success_ids,
				'failed_ids'  => $failed_ids,
				'errors'      => $errors,
			);

		} catch ( \Exception $e ) {
			return array(
				'total'       => 0,
				'success'     => 0,
				'failed'      => 0,
				'success_ids' => array(),
				'failed_ids'  => array(),
				'errors'      => array( $e->getMessage() ),
			);
		}
	}

	/**
	 * Import all categories from Square and sync to WooCommerce
	 *
	 * @return int Number of categories imported
	 */
	public function import_all_from_square() {
		try {
			$total_categories = 0;
			$success_count    = 0;
			$failed_count     = 0;
			$errors           = array();

			$categories_response = $this->api->get_all_square_categories();
			if ( is_wp_error( $categories_response ) ) {
				return 0;
			}

			$total_categories = is_array( $categories_response ) ? count( $categories_response ) : 0;

			foreach ( $categories_response as $category_object ) {
				try {
					if ( ! isset( $category_object['id'] ) || ! isset( $category_object['name'] ) ) {
						++$failed_count;
						$errors[] = 'Invalid Square category object';
						continue;
					}

					$square_id = $category_object['id'];
					$name      = $category_object['name'];
					$version   = isset( $category_object['version'] ) ? $category_object['version'] : '';

					// Try to find WooCommerce category by Square ID
					$term_id = $this->find_category_by_square_id( $square_id );
					if ( ! $term_id ) {
						// Try to find by name
						$term = get_term_by( 'name', $name, 'product_cat' );
						if ( $term && ! is_wp_error( $term ) ) {
							$term_id = $term->term_id;
						}
					}

					if ( $term_id ) {
						// Update category name to match Square
						wp_update_term( $term_id, 'product_cat', array( 'name' => $name ) );
					} else {
						// Create new category
						$new_term = wp_insert_term( $name, 'product_cat' );
						if ( is_wp_error( $new_term ) ) {
							++$failed_count;
							$errors[] = sprintf( 'Failed to create category "%s": %s', $name, $new_term->get_error_message() );
							continue;
						}
						$term_id = $new_term['term_id'];
					}

					// Update term meta with Square ID and version
					update_term_meta( $term_id, '_square_id', $square_id );
					if ( $version ) {
						update_term_meta( $term_id, '_square_version', $version );
					}
					++$success_count;
				} catch ( \Throwable $e ) {
					++$failed_count;
					$errors[] = sprintf(
						'Category "%s": %s',
						isset( $category_object['name'] ) ? $category_object['name'] : 'Unknown',
						$e->getMessage()
					);
				}
			}

			return $success_count;
		} catch ( \Throwable $e ) {
			return 0;
		}
	}
}
