<?php
/**
 * Pushes WooCommerce coupons to Google Sheets.
 *
 * @package StoreSheet
 */

declare( strict_types=1 );

namespace StoreSheet\Sync\WcToSheets;

defined( 'ABSPATH' ) || exit;

use StoreSheet\API\GoogleSheetsClient;
use StoreSheet\Sync\RowMapper;

class CouponPusher {

	private const TAB = 'Coupons';

	private GoogleSheetsClient $client;
	private RowMapper $mapper;

	public function __construct( GoogleSheetsClient $client, RowMapper $mapper ) {
		$this->client = $client;
		$this->mapper = $mapper;
	}

	/**
	 * Push or update a single coupon.
	 *
	 * @param int $coupon_id Post ID of the coupon.
	 * @return true|\WP_Error
	 */
	public function push( int $coupon_id ) {
		$coupon = new \WC_Coupon( $coupon_id );
		if ( ! $coupon->get_id() ) {
			return new \WP_Error( 'invalid_coupon', "Coupon {$coupon_id} not found." );
		}

		$row_index = $this->get_row_index( $coupon_id );

		/** This filter is documented in includes/Sync/WcToSheets/ProductPusher.php. */
		if ( apply_filters( 'storesheet_skip_push', false, self::TAB, $row_index, $coupon->get_date_modified(), 'coupon' ) ) {
			storesheet()->log( "Coupon {$coupon_id} conflict skip — not overwriting the Sheets row.", 'debug' );
			return true;
		}

		$row = $this->mapper->coupon_to_row( $coupon );

		if ( $row_index ) {
			$result = $this->client->batch_update(
				array(
					array(
						'range'  => self::TAB . '!A' . $row_index . ':N' . $row_index,
						'values' => array( $row ),
					),
				)
			);
		} else {
			$result = $this->client->append( self::TAB . '!A:N', array( $row ) );
			if ( ! is_wp_error( $result ) ) {
				$new_index = $this->parse_appended_row_index( $result );
				if ( $new_index ) {
					$this->save_row_index( $coupon_id, $new_index );
				}
			}
		}

		if ( is_wp_error( $result ) ) {
			$this->log_sync( $coupon_id, 'failed', $result->get_error_message() );
			return $result;
		}

		$this->log_sync( $coupon_id, 'success' );
		return true;
	}

	/**
	 * Push all coupons — for full sync.
	 *
	 * @return int|\WP_Error
	 */
	public function push_all( int $batch_size = -1, int $offset = 0 ) {
		$ids = get_posts(
			array(
				'post_type'      => 'shop_coupon',
				'post_status'    => 'publish',
				'posts_per_page' => -1,
				'fields'         => 'ids',
			)
		);

		if ( empty( $ids ) ) {
			return 0;
		}

		// Route each coupon through the single-item push so the row map stays
		// authoritative. The previous clear()+append() rewrote the tab but left
		// storesheet_row_map pointing at the old offsets, so the next single
		// coupon edit would batch_update the wrong (post-rewrite) row.
		$pushed = 0;
		foreach ( $ids as $id ) {
			$coupon = new \WC_Coupon( (int) $id );
			if ( ! $coupon->get_id() ) {
				continue;
			}
			$result = $this->push( (int) $id );
			if ( is_wp_error( $result ) ) {
				return $result;
			}
			++$pushed;
		}

		return $pushed;
	}

	// -------------------------------------------------------------------------
	// Helpers
	// -------------------------------------------------------------------------

	private function get_row_index( int $coupon_id ): ?int {
		global $wpdb;
		$settings = get_option( 'storesheet_settings', array() );
		$sheet_id = $settings['spreadsheet_id'] ?? '';

		$row = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prepare(
				"SELECT row_index FROM {$wpdb->prefix}storesheet_row_map WHERE tab_name = %s AND resource = 'coupon' AND resource_id = %d AND sheet_id = %s LIMIT 1",
				self::TAB,
				$coupon_id,
				$sheet_id
			)
		);

		return $row ? (int) $row : null;
	}

	private function save_row_index( int $coupon_id, int $row_index ): void {
		global $wpdb;
		$settings = get_option( 'storesheet_settings', array() );
		$sheet_id = $settings['spreadsheet_id'] ?? '';

		$wpdb->replace( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prefix . 'storesheet_row_map',
			array(
				'tab_name'    => self::TAB,
				'resource'    => 'coupon',
				'resource_id' => $coupon_id,
				'row_index'   => $row_index,
				'sheet_id'    => $sheet_id,
			),
			array( '%s', '%s', '%d', '%d', '%s' )
		);
	}

	private function parse_appended_row_index( array $result ): ?int {
		$range = $result['updates']['updatedRange'] ?? '';
		if ( preg_match( '/(\d+)$/', $range, $m ) ) {
			return (int) $m[1];
		}
		return null;
	}

	private function log_sync( int $coupon_id, string $status, string $message = '' ): void {
		global $wpdb;
		$wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->prefix . 'storesheet_sync_log',
			array(
				'direction'   => 'wc_to_sheets',
				'resource'    => 'coupon',
				'resource_id' => $coupon_id,
				'tab_name'    => self::TAB,
				'status'      => $status,
				'message'     => $message,
			),
			array( '%s', '%s', '%d', '%s', '%s', '%s' )
		);
	}
}
