<?php

/**
 * WooWriteHandler — WooCommerce write actions.
 *
 * Owns: wc_update_product, wc_update_order_status, wc_create_product,
 *       wc_manage_categories, wc_manage_coupons
 *
 * @package LolaCore\Actions\Handlers
 * @license GPL-2.0-or-later
 */

declare( strict_types=1 );

namespace LolaCore\Actions\Handlers;

use LolaCore\Actions\Contracts\ActionHandlerInterface;

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

class WooWriteHandler implements ActionHandlerInterface {

	public function getSupportedActions(): array {
		return array( 'wc_update_product', 'wc_update_order_status', 'wc_create_product', 'wc_manage_categories', 'wc_manage_coupons' );
	}

	public function handle( string $actionId, array $params, bool $dryRun ): array {
		$this->requireWooCommerce();
		return match ( $actionId ) {
			'wc_update_product'      => $this->updateProduct( $params, $dryRun ),
			'wc_update_order_status' => $this->updateOrderStatus( $params, $dryRun ),
			'wc_create_product'      => $this->createProduct( $params, $dryRun ),
			'wc_manage_categories'   => $this->manageCategories( $params, $dryRun ),
			'wc_manage_coupons'      => $this->manageCoupons( $params, $dryRun ),
			default                  => throw new \Exception( esc_html( "WooWriteHandler: unknown action '{$actionId}'." ) ),
		};
	}

	private function requireWooCommerce(): void {
		if ( ! class_exists( 'WooCommerce' ) ) {
			throw new \Exception( 'WooCommerce is not installed or activated.' );
		}
	}

	private function resolveTermNames( array $termIds, string $taxonomy ): array {
		$names = array();
		foreach ( $termIds as $id ) {
			$t = get_term( (int) $id, $taxonomy );
			if ( $t && ! is_wp_error( $t ) ) { $names[] = $t->name . ' (#' . $t->term_id . ')'; }
		}
		return $names;
	}

	private function applyCouponRestrictions( \WC_Coupon $coupon, array $params ): void {
		if ( isset( $params['product_categories'] ) && is_array( $params['product_categories'] ) ) { $coupon->set_product_categories( array_map( 'intval', $params['product_categories'] ) ); }
		if ( isset( $params['excluded_product_categories'] ) && is_array( $params['excluded_product_categories'] ) ) { $coupon->set_excluded_product_categories( array_map( 'intval', $params['excluded_product_categories'] ) ); }
		if ( isset( $params['product_ids'] ) && is_array( $params['product_ids'] ) ) { $coupon->set_product_ids( array_map( 'intval', $params['product_ids'] ) ); }
		if ( isset( $params['excluded_product_ids'] ) && is_array( $params['excluded_product_ids'] ) ) { $coupon->set_excluded_product_ids( array_map( 'intval', $params['excluded_product_ids'] ) ); }
		if ( isset( $params['email_restrictions'] ) && is_array( $params['email_restrictions'] ) ) { $coupon->set_email_restrictions( array_map( 'sanitize_email', $params['email_restrictions'] ) ); }
		if ( array_key_exists( 'usage_limit_per_user', $params ) ) { $coupon->set_usage_limit_per_user( '' !== $params['usage_limit_per_user'] ? (int) $params['usage_limit_per_user'] : 0 ); }
		if ( isset( $params['maximum_amount'] ) ) { $coupon->set_maximum_amount( wc_format_decimal( $params['maximum_amount'] ) ); }
		if ( isset( $params['free_shipping'] ) ) { $coupon->set_free_shipping( (bool) $params['free_shipping'] ); }
	}

	private function updateProduct( array $params, bool $dryRun ): array {
		$pid = (int) ( $params['product_id'] ?? 0 );
		if ( ! $pid ) { throw new \Exception( 'A valid product_id is required.' ); }
		$p = wc_get_product( $pid );
		if ( ! $p ) { throw new \Exception( 'Product not found.' ); }

		if ( $dryRun ) {
			$catNames = array();
			foreach ( $p->get_category_ids() as $cid ) { $t = get_term( $cid, 'product_cat' ); if ( $t && ! is_wp_error( $t ) ) { $catNames[] = $t->name . ' (#' . $cid . ')'; } }
			return array( 'product_id' => $p->get_id(), 'current' => array( 'name' => $p->get_name(), 'regular_price' => $p->get_regular_price(), 'sale_price' => $p->get_sale_price(), 'stock_status' => $p->get_stock_status(), 'stock_quantity' => $p->get_stock_quantity(), 'status' => $p->get_status(), 'categories' => $catNames, 'sku' => $p->get_sku(), 'weight' => $p->get_weight() ), 'proposed' => $params );
		}

		if ( isset( $params['name'] ) )              { $p->set_name( sanitize_text_field( $params['name'] ) ); }
		if ( isset( $params['regular_price'] ) )     { $p->set_regular_price( wc_format_decimal( $params['regular_price'] ) ); }
		if ( array_key_exists( 'sale_price', $params ) ) { $p->set_sale_price( '' !== $params['sale_price'] ? wc_format_decimal( $params['sale_price'] ) : '' ); }
		if ( isset( $params['stock_quantity'] ) || isset( $params['stock_qty'] ) ) {
			$qty = (int) ( $params['stock_quantity'] ?? $params['stock_qty'] );
			if ( $qty < 0 ) { throw new \Exception( 'Stock quantity cannot be negative.' ); }
			$p->set_manage_stock( true );
			$p->set_stock_quantity( $qty );
		}
		if ( isset( $params['manage_stock'] ) ) { $p->set_manage_stock( (bool) $params['manage_stock'] ); }
		if ( isset( $params['stock_status'] ) ) { $p->set_stock_status( sanitize_text_field( $params['stock_status'] ) ); }
		if ( isset( $params['status'] ) )        { $p->set_status( sanitize_text_field( $params['status'] ) ); }
		if ( isset( $params['sku'] ) )           { $p->set_sku( sanitize_text_field( $params['sku'] ) ); }
		if ( isset( $params['description'] ) )       { $p->set_description( wp_kses_post( $params['description'] ) ); }
		if ( isset( $params['short_description'] ) ) { $p->set_short_description( wp_kses_post( $params['short_description'] ) ); }
		if ( isset( $params['categories'] ) && is_array( $params['categories'] ) ) { $p->set_category_ids( array_map( 'intval', $params['categories'] ) ); }
		if ( isset( $params['tags'] ) && is_array( $params['tags'] ) )              { $p->set_tag_ids( array_map( 'intval', $params['tags'] ) ); }
		if ( isset( $params['weight'] ) ) { $p->set_weight( wc_format_decimal( $params['weight'] ) ); }

		$saved = $p->save();
		if ( is_wp_error( $saved ) ) { throw new \Exception( esc_html( $saved->get_error_message() ) ); }

		$catNames = array();
		foreach ( $p->get_category_ids() as $cid ) { $t = get_term( $cid, 'product_cat' ); if ( $t && ! is_wp_error( $t ) ) { $catNames[] = $t->name; } }
		return array( 'product_id' => $p->get_id(), 'name' => $p->get_name(), 'regular_price' => $p->get_regular_price(), 'sale_price' => $p->get_sale_price(), 'stock_status' => $p->get_stock_status(), 'stock_quantity' => $p->get_stock_quantity(), 'status' => $p->get_status(), 'categories' => $catNames, 'message' => 'Product updated successfully.' );
	}

	private function updateOrderStatus( array $params, bool $dryRun ): array {
		$oid = (int) ( $params['order_id'] ?? 0 );
		if ( ! $oid ) { throw new \Exception( 'A valid order_id is required.' ); }
		$o = wc_get_order( $oid );
		if ( ! $o ) { throw new \Exception( 'Order not found.' ); }

		$new_status  = sanitize_text_field( $params['status'] ?? '' );
		$valid       = array_keys( wc_get_order_statuses() );
		if ( empty( $new_status ) || ( ! in_array( 'wc-' . $new_status, $valid, true ) && ! in_array( $new_status, $valid, true ) ) ) {
			throw new \Exception( 'Invalid order status provided.' );
		}

		$old_status = $o->get_status();
		if ( $dryRun ) { return array( 'order_id' => $oid, 'old_status' => $old_status, 'new_status' => $new_status, 'note' => $params['note'] ?? '' ); }

		$o->update_status( $new_status, isset( $params['note'] ) ? sanitize_textarea_field( $params['note'] ) : '' );
		return array( 'order_id' => $oid, 'old_status' => $old_status, 'new_status' => $o->get_status(), 'message' => 'Order status updated.' );
	}

	private function createProduct( array $params, bool $dryRun ): array {
		$name  = $params['name'] ?? '';
		$price = $params['regular_price'] ?? '';
		if ( empty( $name ) || empty( $price ) ) { throw new \Exception( 'Product name and regular_price are required.' ); }

		if ( $dryRun ) { return array( 'action' => 'Will create WooCommerce product', 'name' => $name, 'regular_price' => $price, 'sale_price' => $params['sale_price'] ?? '', 'sku' => $params['sku'] ?? '', 'status' => $params['status'] ?? 'draft' ); }

		$p = new \WC_Product_Simple();
		$p->set_name( sanitize_text_field( $name ) );
		$p->set_regular_price( wc_format_decimal( $price ) );
		if ( ! empty( $params['sale_price'] ) )        { $p->set_sale_price( wc_format_decimal( $params['sale_price'] ) ); }
		if ( ! empty( $params['description'] ) )       { $p->set_description( wp_kses_post( $params['description'] ) ); }
		if ( ! empty( $params['short_description'] ) ) { $p->set_short_description( wp_kses_post( $params['short_description'] ) ); }
		if ( ! empty( $params['sku'] ) )               { $p->set_sku( sanitize_text_field( $params['sku'] ) ); }
		if ( isset( $params['stock_quantity'] ) )      { $p->set_manage_stock( true ); $p->set_stock_quantity( (int) $params['stock_quantity'] ); }
		$p->set_status( sanitize_text_field( $params['status'] ?? 'draft' ) );
		if ( ! empty( $params['categories'] ) && is_array( $params['categories'] ) ) { $p->set_category_ids( array_map( 'intval', $params['categories'] ) ); }

		$pid = $p->save();
		if ( is_wp_error( $pid ) ) { throw new \Exception( esc_html( $pid->get_error_message() ) ); }
		return array( 'success' => true, 'product_id' => $p->get_id(), 'name' => $p->get_name(), 'price' => $p->get_regular_price(), 'status' => $p->get_status(), 'url' => get_permalink( $p->get_id() ), 'message' => "Product '{$name}' created with ID {$p->get_id()}." );
	}

	private function manageCategories( array $params, bool $dryRun ): array {
		$action = $params['action'] ?? '';
		if ( ! in_array( $action, array( 'create', 'update', 'delete' ), true ) ) { throw new \Exception( "Invalid action. Use 'create', 'update', or 'delete'." ); }

		if ( $action === 'create' ) {
			$name = $params['name'] ?? '';
			if ( empty( $name ) ) { throw new \Exception( 'Category name is required for create.' ); }
			if ( $dryRun ) { return array( 'action' => 'Will create product category', 'name' => $name, 'slug' => $params['slug'] ?? '', 'parent' => $params['parent'] ?? 0 ); }
			$args = array();
			if ( ! empty( $params['slug'] ) )        { $args['slug']        = sanitize_text_field( $params['slug'] ); }
			if ( ! empty( $params['parent'] ) )      { $args['parent']      = (int) $params['parent']; }
			if ( ! empty( $params['description'] ) ) { $args['description'] = sanitize_textarea_field( $params['description'] ); }
			$result = wp_insert_term( $name, 'product_cat', $args );
			if ( is_wp_error( $result ) ) { throw new \Exception( esc_html( $result->get_error_message() ) ); }
			return array( 'success' => true, 'term_id' => $result['term_id'], 'message' => "Product category '{$name}' created." );
		}

		if ( $action === 'update' ) {
			$tid = (int) ( $params['term_id'] ?? 0 );
			if ( $tid <= 0 ) { throw new \Exception( 'term_id is required for update.' ); }
			$t = get_term( $tid, 'product_cat' );
			if ( ! $t || is_wp_error( $t ) ) { throw new \Exception( esc_html( "Product category ID {$tid} not found." ) ); }
			$args = array();
			if ( isset( $params['name'] ) )        { $args['name']        = sanitize_text_field( $params['name'] ); }
			if ( isset( $params['slug'] ) )        { $args['slug']        = sanitize_text_field( $params['slug'] ); }
			if ( isset( $params['parent'] ) )      { $args['parent']      = (int) $params['parent']; }
			if ( isset( $params['description'] ) ) { $args['description'] = sanitize_textarea_field( $params['description'] ); }
			if ( empty( $args ) ) { throw new \Exception( 'Nothing to update.' ); }
			if ( $dryRun ) { return array( 'action' => 'Will update product category', 'term_id' => $tid, 'name' => $t->name, 'changes' => $args ); }
			$result = wp_update_term( $tid, 'product_cat', $args );
			if ( is_wp_error( $result ) ) { throw new \Exception( esc_html( $result->get_error_message() ) ); }
			return array( 'success' => true, 'term_id' => $tid, 'message' => 'Product category updated.' );
		}

		// delete
		$tid = (int) ( $params['term_id'] ?? 0 );
		if ( $tid <= 0 ) { throw new \Exception( 'term_id is required for delete.' ); }
		$t = get_term( $tid, 'product_cat' );
		if ( ! $t || is_wp_error( $t ) ) { throw new \Exception( esc_html( "Product category ID {$tid} not found." ) ); }
		if ( $dryRun ) { return array( 'action' => 'Will delete product category', 'term_id' => $tid, 'name' => $t->name, 'count' => $t->count ); }
		$result = wp_delete_term( $tid, 'product_cat' );
		if ( is_wp_error( $result ) ) { throw new \Exception( esc_html( $result->get_error_message() ) ); }
		return array( 'success' => true, 'term_id' => $tid, 'message' => 'Product category deleted.' );
	}

	private function manageCoupons( array $params, bool $dryRun ): array {
		$action = $params['action'] ?? '';
		if ( ! in_array( $action, array( 'create', 'update', 'delete', 'list', 'get' ), true ) ) { throw new \Exception( "Invalid action. Use 'create', 'update', 'delete', 'list', or 'get'." ); }

		if ( $action === 'list' ) {
			if ( $dryRun ) { return array( 'action' => 'Will list coupons', 'page' => $params['page'] ?? 1 ); }
			$args = array(
				'post_type'      => 'shop_coupon',
				'post_status'    => 'publish',
				'posts_per_page' => $params['limit'] ?? 10,
				'paged'          => $params['page'] ?? 1,
			);
			$query = new \WP_Query( $args );
			$data = array();
			foreach ( $query->posts as $post ) {
			    $c = new \WC_Coupon( $post->ID );
				$data[] = array(
					'id'            => $c->get_id(),
					'code'          => $c->get_code(),
					'discount_type' => $c->get_discount_type(),
					'amount'        => $c->get_amount(),
					'usage_limit'   => $c->get_usage_limit(),
					'expiry_date'   => $c->get_date_expires() ? $c->get_date_expires()->date( 'Y-m-d' ) : null,
				);
			}
			return array( 'success' => true, 'total' => $query->found_posts, 'pages' => $query->max_num_pages, 'coupons' => $data );
		}

		if ( $action === 'get' ) {
			$cid = (int) ( $params['coupon_id'] ?? 0 );
			if ( $cid <= 0 ) { throw new \Exception( 'coupon_id is required for get.' ); }
			if ( $dryRun ) { return array( 'action' => 'Will get coupon details', 'coupon_id' => $cid ); }
			$c = new \WC_Coupon( $cid );
			if ( ! $c->get_id() ) { throw new \Exception( esc_html( "Coupon ID {$cid} not found." ) ); }
			return array(
				'success' => true,
				'coupon' => array(
					'id'            => $c->get_id(),
					'code'          => $c->get_code(),
					'discount_type' => $c->get_discount_type(),
					'amount'        => $c->get_amount(),
					'usage_limit'   => $c->get_usage_limit(),
					'usage_limit_per_user' => $c->get_usage_limit_per_user(),
					'expiry_date'   => $c->get_date_expires() ? $c->get_date_expires()->date( 'Y-m-d' ) : null,
					'minimum_amount' => $c->get_minimum_amount(),
					'maximum_amount' => $c->get_maximum_amount(),
					'individual_use' => $c->get_individual_use(),
					'free_shipping'  => $c->get_free_shipping(),
				)
			);
		}

		if ( $action === 'create' ) {
			$code = $params['code'] ?? '';
			if ( empty( $code ) ) { throw new \Exception( 'Coupon code is required for create.' ); }
			if ( $dryRun ) {
				$preview = array( 'action' => 'Will create coupon', 'code' => $code, 'discount_type' => $params['discount_type'] ?? 'percent', 'amount' => $params['amount'] ?? '0' );
				if ( ! empty( $params['product_categories'] ) ) { $preview['restricted_to_categories'] = $this->resolveTermNames( $params['product_categories'], 'product_cat' ); }
				if ( ! empty( $params['product_ids'] ) ) { $preview['restricted_to_product_ids'] = $params['product_ids']; }
				if ( ! empty( $params['email_restrictions'] ) ) { $preview['restricted_to_emails'] = $params['email_restrictions']; }
				return $preview;
			}
			$c = new \WC_Coupon();
			$c->set_code( sanitize_text_field( $code ) );
			$c->set_discount_type( sanitize_text_field( $params['discount_type'] ?? 'percent' ) );
			$c->set_amount( wc_format_decimal( $params['amount'] ?? '0' ) );
			if ( isset( $params['usage_limit'] ) )  { $c->set_usage_limit( (int) $params['usage_limit'] ); }
			if ( isset( $params['expiry_date'] ) ) { $c->set_date_expires( '' !== $params['expiry_date'] ? sanitize_text_field( $params['expiry_date'] ) : null ); }
			if ( isset( $params['minimum_amount'] ) ) { $c->set_minimum_amount( wc_format_decimal( $params['minimum_amount'] ) ); }
			if ( isset( $params['individual_use'] ) ) { $c->set_individual_use( (bool) $params['individual_use'] ); }
			$this->applyCouponRestrictions( $c, $params );
			$cid      = $c->save();
			$response = array( 'success' => true, 'coupon_id' => $cid, 'code' => $c->get_code(), 'message' => "Coupon '{$code}' created." );
			if ( $c->get_product_categories() ) { $response['product_categories'] = $this->resolveTermNames( $c->get_product_categories(), 'product_cat' ); }
			return $response;
		}

		if ( $action === 'update' ) {
			$cid = (int) ( $params['coupon_id'] ?? 0 );
			if ( $cid <= 0 ) { throw new \Exception( 'coupon_id is required for update.' ); }
			$c = new \WC_Coupon( $cid );
			if ( ! $c->get_id() ) { throw new \Exception( esc_html( "Coupon ID {$cid} not found." ) ); }
			if ( $dryRun ) { $allowed = array( 'amount', 'discount_type', 'usage_limit', 'usage_limit_per_user', 'expiry_date', 'minimum_amount', 'maximum_amount', 'individual_use', 'free_shipping', 'product_categories', 'excluded_product_categories', 'product_ids', 'excluded_product_ids', 'email_restrictions' ); return array( 'action' => 'Will update coupon', 'coupon_id' => $cid, 'code' => $c->get_code(), 'changes' => array_intersect_key( $params, array_flip( $allowed ) ) ); }
			if ( isset( $params['amount'] ) )        { $c->set_amount( wc_format_decimal( $params['amount'] ) ); }
			if ( isset( $params['discount_type'] ) ) { $c->set_discount_type( sanitize_text_field( $params['discount_type'] ) ); }
			if ( isset( $params['usage_limit'] ) )   { $c->set_usage_limit( (int) $params['usage_limit'] ); }
			if ( isset( $params['expiry_date'] ) )     { $c->set_date_expires( '' !== $params['expiry_date'] ? sanitize_text_field( $params['expiry_date'] ) : null ); }
			if ( isset( $params['minimum_amount'] ) )  { $c->set_minimum_amount( wc_format_decimal( $params['minimum_amount'] ) ); }
			if ( isset( $params['individual_use'] ) )    { $c->set_individual_use( (bool) $params['individual_use'] ); }
			$this->applyCouponRestrictions( $c, $params );
			$c->save();
			return array( 'success' => true, 'coupon_id' => $cid, 'message' => 'Coupon updated.' );
		}

		// delete
		$cid = (int) ( $params['coupon_id'] ?? 0 );
		if ( $cid <= 0 ) { throw new \Exception( 'coupon_id is required for delete.' ); }
		$c = new \WC_Coupon( $cid );
		if ( ! $c->get_id() ) { throw new \Exception( esc_html( "Coupon ID {$cid} not found." ) ); }
		if ( $dryRun ) { return array( 'action' => 'Will delete coupon', 'coupon_id' => $cid, 'code' => $c->get_code() ); }
		$result = wp_delete_post( $cid, true );
		return array( 'success' => (bool) $result, 'message' => $result ? 'Coupon deleted.' : 'Failed to delete coupon.' );
	}
}
