<?php

namespace ShopManagerPro\Products;

use ShopManagerPro\Products\DTO\Generated\Product;
use ShopManagerPro\Products\DTO\Generated\ProductBulkUpdate;
use ShopManagerPro\Products\Fields\DTO\ProductFieldGroupType;
use ShopManagerPro\Shared\Utils\JSON;

class ProductAPI {
	public const validStockStatuses = ['instock', 'onbackorder', 'outofstock'];
	public const validTaxStatuses = ['none', 'shipping', 'taxable'];
	public const validPostStatuses = ['draft', 'pending', 'private', 'publish', 'trash'];

	public static function registerRoutes() {
		register_rest_route(\ShopManagerPro\Shared\Utils\Constants::API_NAMESPACE, '/products/get', [['methods' => 'GET', 'callback' => [self::class, 'getProducts'], 'permission_callback' => [\ShopManagerPro\Shared\CapabilityService::class, 'requireReadCapability']], 'schema' => fn () => self::getProductsSchema()]);
		register_rest_route(\ShopManagerPro\Shared\Utils\Constants::API_NAMESPACE, '/products/update/(?P<id>\d+)', [['methods' => 'PUT', 'callback' => [self::class, 'updateProduct'], 'permission_callback' => [\ShopManagerPro\Shared\CapabilityService::class, 'requireEditCapability'], 'args' => self::getProductEditSchema()], 'schema' => fn () => []]);
		register_rest_route(\ShopManagerPro\Shared\Utils\Constants::API_NAMESPACE, '/products/bulkUpdate', [['methods' => 'POST', 'callback' => [self::class, 'bulkUpdateProducts'], 'permission_callback' => [\ShopManagerPro\Shared\CapabilityService::class, 'requireEditCapability'], 'args' => self::getProductBulkEditSchema(false)], 'schema' => fn () => ['title' => 'productsBulkUpdate', 'type' => 'object', 'required' => ['jobId'], 'properties' => ['jobId' => ['type' => 'number']]]]);
	}

	public static function getProducts(\WP_REST_Request $request) {
		$products = ProductRepository::getProducts();
		$products = self::normalizeProductResponse($products);

		return rest_ensure_response($products);
	}

	public static function updateProduct(\WP_REST_Request $request) {
		$id = intval($request['id']);
		$updatedProduct = self::normalizeProductRequest($request->get_params());
		$wcProduct = wc_get_product($id);
		if (!$wcProduct) {
			return new \WP_REST_Response(['success' => false, 'message' => sprintf('Product with ID %d not found', $id)], 404);
		} ProductRepository::updateProduct($wcProduct, $updatedProduct);

		return new \WP_REST_Response(['success' => true, 'message' => sprintf('Product with ID %d updated successfully', $id)], 200);
	}

	public static function bulkUpdateProducts(\WP_REST_Request $request) {
		$body = $request->get_body();
		$params = json_decode($body, flags: JSON_THROW_ON_ERROR);
		$params = JSON::removeEmptyObjects($params);
		$bulkUpdate = ProductBulkUpdate::buildFromInput($params);
		$jobID = \ShopManagerPro\Jobs\JobRepository::createProductUpdateJob($bulkUpdate);

		return new \WP_REST_Response(['jobId' => $jobID], 200);
	}

	public static function init() {
		add_action('rest_api_init', [self::class, 'registerRoutes']);
	}

	public static function getProductSchema() {
		return Fields\ProductFieldRepository::getProductSchema();
	}

	public static function getProductsSchema() {
		$schema = ['title' => 'products', 'type' => 'array', 'items' => self::getProductSchema()];

		return ['title' => 'products', 'type' => 'array', 'items' => self::getProductSchema()];
	}

	public static function getProductChangeSchema() {
		$schema = self::getProductSchema();
		$schema = $schema['properties'];
		unset($schema['basic']['required']);
		foreach ($schema as &$productFieldType) {
			if (isset($productFieldType['properties'])) {
				foreach ($productFieldType['properties'] as $key => $prop) {
					$productFieldType['properties'][$key] = ['type' => 'object', 'additionalProperties' => false, 'required' => ['old', 'new'], 'properties' => ['old' => $prop, 'new' => $prop]];
				}
			} elseif (isset($productFieldType['additionalProperties'])) {
				$productFieldType['properties'] = ['old' => ['type' => 'object', 'additionalProperties' => $productFieldType['additionalProperties']], 'new' => ['type' => 'object', 'additionalProperties' => $productFieldType['additionalProperties']]];
				$productFieldType['required'] = ['old', 'new'];
				$productFieldType['additionalProperties'] = false;
			}
		}

return $schema;
	}

	private static function getProductEditSchema() {
		$schema = self::getProductSchema();
		$schema = $schema['properties'];
		$schema['id'] = ['type' => 'integer', 'validate_callback' => fn ($param) => is_numeric($param) && intval($param) > 0];

		return $schema;
	}

	public static function getProductBulkEditSchema(bool $jsonSchema) {
		$schema = self::getProductSchema();
		$productGroupUpdate = ['type' => 'array', 'items' => ['type' => 'object', 'required' => ['key', 'values'], 'additionalProperties' => false, 'properties' => ['key' => ['type' => 'string'], 'values' => ['type' => 'array']]]];
		$schema = ['productIds' => ['type' => 'array', 'items' => ['type' => 'integer']], 'actions' => ['type' => 'object', 'additionalProperties' => false, 'properties' => ['basic' => $schema['properties']['basic'], 'special' => ['type' => 'object', 'additionalProperties' => false, 'properties' => ['regularPriceMode' => ['type' => 'string', 'enum' => ['fixed', 'absolute', 'percentage', 'clear']], 'regularPricePercentage' => ['type' => 'number'], 'regularPriceAbsolute' => ['type' => 'number'], 'regularPriceUseSaleAsReference' => ['type' => 'boolean'], 'salePriceMode' => ['type' => 'string', 'enum' => ['fixed', 'absolute', 'percentage', 'clear']], 'salePricePercentage' => ['type' => 'number'], 'salePriceAbsolute' => ['type' => 'number'], 'salePriceUseRegularAsReference' => ['type' => 'boolean'], 'productGroupUpdates' => ['type' => 'object', 'additionalProperties' => false, 'properties' => ['add' => $productGroupUpdate, 'remove' => $productGroupUpdate]]]]]]];
		unset($schema['actions']['properties']['basic']['required']);
		if ($jsonSchema) {
			$schema = ['title' => 'productsBulkUpdate', 'type' => 'object', 'required' => ['productIds', 'actions'], 'properties' => $schema];
		} else {
			$schema['actions']['required'] = true;
			$schema['productIds']['required'] = true;
		}

return $schema;
	}

	private static function normalizeProductRequest(array $body) {
		$allowedKeys = array_keys(self::getProductSchema()['properties']);
		$body = array_filter($body, fn ($key) => in_array($key, $allowedKeys, true), ARRAY_FILTER_USE_KEY);
		$body = JSON::encode($body);
		$body = json_decode($body);
		foreach (ProductFieldGroupType::cases() as $fieldGroupType) {
			$propertyName = $fieldGroupType->value;
			if (isset($body->{$propertyName}) && is_array($body->{$propertyName}) && empty($body->{$propertyName})) {
				$body->{$propertyName} = new \stdClass();
			}
		}

return Product::buildFromInput($body);
	}

	private static function normalizeProductResponse(array $products) {
		$result = [];
		foreach ($products as $product) {
			$product = $product->toJson();
			if (!$product[ProductFieldGroupType::ACF->value]) {
				$product[ProductFieldGroupType::ACF->value] = new \stdClass();
			} if (!$product[ProductFieldGroupType::DEFAULT_TAXONOMY->value]) {
				$product[ProductFieldGroupType::DEFAULT_TAXONOMY->value] = new \stdClass();
			} if (!$product[ProductFieldGroupType::PRODUCT_ATTRIBUTE->value]) {
				$product[ProductFieldGroupType::PRODUCT_ATTRIBUTE->value] = new \stdClass();
			} $result[] = $product;
		}

return $result;
	}
}
