<?php
/**
 * Google Merchant Feed Manager
 *
 * Manages multiple feed configurations (CRUD operations).
 *
 * @package GGM_Commerce
 * @since 1.0.0
 */

defined( 'ABSPATH' ) || exit;

/**
 * Class GGM_Commerce_Google_Merchant_Feed_Manager
 *
 * Handles creation, retrieval, update, and deletion of feed configurations.
 */
class GGM_Commerce_Google_Merchant_Feed_Manager {

	/**
	 * Option name for feeds storage.
	 */
	const OPTION_NAME = 'ggm_commerce_google_merchant_feeds';

	/**
	 * Singleton instance.
	 *
	 * @var GGM_Commerce_Google_Merchant_Feed_Manager|null
	 */
	private static $instance = null;

	/**
	 * Cached feeds.
	 *
	 * @var array|null
	 */
	private $feeds = null;

	/**
	 * Default feed configuration.
	 *
	 * @var array
	 */
	private $feed_defaults = array(
		'id'              => '',
		'name'            => '',
		'status'          => 'active', // 'active' or 'paused'.
		'categories'      => array(),  // Empty = all categories.
		'exclude_categories' => array(),
		'stock_status'    => 'all',    // 'all', 'instock', 'outofstock'.
		'sale_only'       => false,
		'featured_only'   => false,
		'schedule'        => 'daily',  // 'hourly', 'twicedaily', 'daily', 'weekly'.
		'last_generated'  => null,
		'product_count'   => 0,
		'error_count'     => 0,
		'created_at'      => null,
		'updated_at'      => null,
	);

	/**
	 * Get singleton instance.
	 *
	 * @return GGM_Commerce_Google_Merchant_Feed_Manager
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Private constructor for singleton.
	 */
	private function __construct() {}

	/**
	 * Get all feeds.
	 *
	 * @return array
	 */
	public function get_feeds() {
		if ( null === $this->feeds ) {
			$this->feeds = get_option( self::OPTION_NAME, array() );
		}
		return $this->feeds;
	}

	/**
	 * Get a single feed by ID.
	 *
	 * @param string $feed_id Feed ID.
	 * @return array|null Feed data or null if not found.
	 */
	public function get_feed( $feed_id ) {
		$feeds = $this->get_feeds();
		return $feeds[ $feed_id ] ?? null;
	}

	/**
	 * Create a new feed.
	 *
	 * @param array $data Feed data.
	 * @return array|WP_Error Created feed or error.
	 */
	public function create_feed( $data ) {
		$feeds = $this->get_feeds();

		// Generate ID if not provided.
		if ( empty( $data['id'] ) ) {
			$data['id'] = $this->generate_feed_id( $data['name'] ?? 'feed' );
		}

		// Check for duplicate ID.
		if ( isset( $feeds[ $data['id'] ] ) ) {
			return new WP_Error( 'duplicate_id', __( 'A feed with this ID already exists.', 'ggm-commerce' ) );
		}

		// Validate required fields.
		if ( empty( $data['name'] ) ) {
			return new WP_Error( 'missing_name', __( 'Feed name is required.', 'ggm-commerce' ) );
		}

		// Merge with defaults.
		$feed = wp_parse_args( $data, $this->feed_defaults );

		// Set timestamps.
		$feed['created_at'] = current_time( 'mysql' );
		$feed['updated_at'] = current_time( 'mysql' );

		// Sanitize.
		$feed = $this->sanitize_feed( $feed );

		// Save.
		$feeds[ $feed['id'] ] = $feed;
		$this->save_feeds( $feeds );

		return $feed;
	}

	/**
	 * Update an existing feed.
	 *
	 * @param string $feed_id Feed ID.
	 * @param array  $data    Feed data to update.
	 * @return array|WP_Error Updated feed or error.
	 */
	public function update_feed( $feed_id, $data ) {
		$feeds = $this->get_feeds();

		if ( ! isset( $feeds[ $feed_id ] ) ) {
			return new WP_Error( 'not_found', __( 'Feed not found.', 'ggm-commerce' ) );
		}

		// Prevent ID change.
		unset( $data['id'] );
		unset( $data['created_at'] );

		// Merge with existing.
		$feed = wp_parse_args( $data, $feeds[ $feed_id ] );

		// Update timestamp.
		$feed['updated_at'] = current_time( 'mysql' );

		// Sanitize.
		$feed = $this->sanitize_feed( $feed );

		// Save.
		$feeds[ $feed_id ] = $feed;
		$this->save_feeds( $feeds );

		return $feed;
	}

	/**
	 * Delete a feed.
	 *
	 * @param string $feed_id Feed ID.
	 * @return bool True on success.
	 */
	public function delete_feed( $feed_id ) {
		$feeds = $this->get_feeds();

		if ( ! isset( $feeds[ $feed_id ] ) ) {
			return false;
		}

		unset( $feeds[ $feed_id ] );
		$this->save_feeds( $feeds );

		// Delete the generated feed file.
		$this->delete_feed_file( $feed_id );

		return true;
	}

	/**
	 * Update feed generation stats.
	 *
	 * @param string $feed_id       Feed ID.
	 * @param int    $product_count Number of products in feed.
	 * @param int    $error_count   Number of products with errors.
	 * @return bool
	 */
	public function update_feed_stats( $feed_id, $product_count, $error_count = 0 ) {
		return $this->update_feed(
			$feed_id,
			array(
				'last_generated' => current_time( 'mysql' ),
				'product_count'  => $product_count,
				'error_count'    => $error_count,
			)
		);
	}

	/**
	 * Get active feeds for scheduling.
	 *
	 * @return array
	 */
	public function get_active_feeds() {
		$feeds  = $this->get_feeds();
		$active = array();

		foreach ( $feeds as $feed_id => $feed ) {
			if ( 'active' === $feed['status'] ) {
				$active[ $feed_id ] = $feed;
			}
		}

		return $active;
	}

	/**
	 * Get feeds by schedule interval.
	 *
	 * @param string $schedule Schedule interval (hourly, twicedaily, daily, weekly).
	 * @return array
	 */
	public function get_feeds_by_schedule( $schedule ) {
		$active   = $this->get_active_feeds();
		$matching = array();

		foreach ( $active as $feed_id => $feed ) {
			if ( $feed['schedule'] === $schedule ) {
				$matching[ $feed_id ] = $feed;
			}
		}

		return $matching;
	}

	/**
	 * Generate a unique feed ID from name.
	 *
	 * @param string $name Feed name.
	 * @return string
	 */
	private function generate_feed_id( $name ) {
		$base = sanitize_title( $name );
		$id   = $base;
		$i    = 1;

		$feeds = $this->get_feeds();

		while ( isset( $feeds[ $id ] ) ) {
			$id = $base . '-' . $i;
			++$i;
		}

		return $id;
	}

	/**
	 * Sanitize feed data.
	 *
	 * @param array $feed Feed data.
	 * @return array
	 */
	private function sanitize_feed( $feed ) {
		$sanitized = array();

		$sanitized['id']   = sanitize_key( $feed['id'] );
		$sanitized['name'] = sanitize_text_field( $feed['name'] );

		$sanitized['status'] = in_array( $feed['status'], array( 'active', 'paused' ), true )
			? $feed['status']
			: 'active';

		$sanitized['categories'] = array_map( 'absint', (array) ( $feed['categories'] ?? array() ) );
		$sanitized['exclude_categories'] = array_map( 'absint', (array) ( $feed['exclude_categories'] ?? array() ) );

		$sanitized['stock_status'] = in_array( $feed['stock_status'], array( 'all', 'instock', 'outofstock' ), true )
			? $feed['stock_status']
			: 'all';

		$sanitized['sale_only']     = (bool) ( $feed['sale_only'] ?? false );
		$sanitized['featured_only'] = (bool) ( $feed['featured_only'] ?? false );

		$valid_schedules         = array( 'hourly', 'twicedaily', 'daily', 'weekly' );
		$sanitized['schedule']   = in_array( $feed['schedule'], $valid_schedules, true )
			? $feed['schedule']
			: 'daily';

		$sanitized['last_generated'] = $feed['last_generated'] ?? null;
		$sanitized['product_count']  = absint( $feed['product_count'] ?? 0 );
		$sanitized['error_count']    = absint( $feed['error_count'] ?? 0 );
		$sanitized['created_at']     = $feed['created_at'] ?? null;
		$sanitized['updated_at']     = $feed['updated_at'] ?? null;

		return $sanitized;
	}

	/**
	 * Save feeds to database.
	 *
	 * @param array $feeds Feeds data.
	 * @return bool
	 */
	private function save_feeds( $feeds ) {
		$this->feeds = $feeds;
		return update_option( self::OPTION_NAME, $feeds );
	}

	/**
	 * Delete the generated XML file for a feed.
	 *
	 * @param string $feed_id Feed ID.
	 * @return bool
	 */
	private function delete_feed_file( $feed_id ) {
		$upload_dir = wp_upload_dir();
		$feed_dir   = $upload_dir['basedir'] . '/ggm-commerce-feeds';
		$file_path  = $feed_dir . '/google-feed-' . $feed_id . '.xml';

		if ( file_exists( $file_path ) ) {
			return wp_delete_file( $file_path );
		}

		return true;
	}

	/**
	 * Get the file path for a feed.
	 *
	 * @param string $feed_id Feed ID.
	 * @return string
	 */
	public function get_feed_file_path( $feed_id ) {
		$upload_dir = wp_upload_dir();
		$feed_dir   = $upload_dir['basedir'] . '/ggm-commerce-feeds';
		return $feed_dir . '/google-feed-' . sanitize_file_name( $feed_id ) . '.xml';
	}

	/**
	 * Get the URL for a feed.
	 *
	 * @param string $feed_id Feed ID.
	 * @return string
	 */
	public function get_feed_url( $feed_id ) {
		return rest_url( 'ggm-commerce/v1/google-feed/' . sanitize_key( $feed_id ) );
	}

	/**
	 * Get schedule options.
	 *
	 * @return array
	 */
	public function get_schedule_options() {
		return array(
			'hourly'     => __( 'Hourly', 'ggm-commerce' ),
			'twicedaily' => __( 'Twice Daily', 'ggm-commerce' ),
			'daily'      => __( 'Daily', 'ggm-commerce' ),
			'weekly'     => __( 'Weekly', 'ggm-commerce' ),
		);
	}

	/**
	 * Get stock status options.
	 *
	 * @return array
	 */
	public function get_stock_status_options() {
		return array(
			'all'        => __( 'All Products', 'ggm-commerce' ),
			'instock'    => __( 'In Stock Only', 'ggm-commerce' ),
			'outofstock' => __( 'Out of Stock Only', 'ggm-commerce' ),
		);
	}

	/**
	 * Create default feed if none exist.
	 *
	 * @return void
	 */
	public function maybe_create_default_feed() {
		$feeds = $this->get_feeds();

		if ( empty( $feeds ) ) {
			$this->create_feed(
				array(
					'id'   => 'default',
					'name' => __( 'Main Product Feed', 'ggm-commerce' ),
				)
			);
		}
	}
}
