<?php

namespace ShopManagerPro\Products\Fields;

use ShopManagerPro\ACF\DTO\ACFField as ACFFieldData;
use ShopManagerPro\Products\Fields\DTO\ACF\ACFField;
use ShopManagerPro\Products\Fields\DTO\ACF\ACFFieldGroup;
use ShopManagerPro\Products\Fields\DTO\ACF\ACFGroupedFields;
use ShopManagerPro\Products\Fields\DTO\AllProductFields;
use ShopManagerPro\Products\Fields\DTO\Basic\BasicField;
use ShopManagerPro\Products\Fields\DTO\Basic\BasicFieldGroup;
use ShopManagerPro\Products\Fields\DTO\Basic\BasicFieldKeys;
use ShopManagerPro\Products\Fields\DTO\CustomMeta\CustomMetaGroup;
use ShopManagerPro\Products\Fields\DTO\DefaultTaxonomy\DefaultTaxonomyField;
use ShopManagerPro\Products\Fields\DTO\DefaultTaxonomy\DefaultTaxonomyFieldGroup;
use ShopManagerPro\Products\Fields\DTO\DefaultTaxonomy\DefaultTaxonomyValue;
use ShopManagerPro\Products\Fields\DTO\ProductAttributes\ProductAttributeField;
use ShopManagerPro\Products\Fields\DTO\ProductAttributes\ProductAttributeFieldGroup;
use ShopManagerPro\Products\Fields\DTO\ProductAttributes\ProductAttributeValue;
use ShopManagerPro\Products\Fields\DTO\ProductFieldType;
use ShopManagerPro\Products\ProductAPI;
use ShopManagerPro\Taxonomies\TaxonomyRepository;

class ProductFieldRepository {
	private static array $acfFields = [];
	private static array $taxonomies = [];
	private static ?array $productFieldSchemaCache = null;
	private static ?array $productSchemaCache = null;

	public static function getProductFields(bool $withData) {
		$acfFields = [];
		$taxonomies = [];
		if ($withData) {
			$acfFields = self::getACFFieldData();
			$taxonomies = self::getTaxonomyData();
		}

return new AllProductFields(acf: self::getACFFields($acfFields), basic: self::getBasicFields(), customMeta: self::getCustomMetaFields(), defaultTaxonomies: self::getDefaultTaxonomies($taxonomies), productAttributes: self::getProductAttributes($taxonomies));
	}

	public static function getProductFieldsSchema() {
		if (!self::$productFieldSchemaCache) {
			self::$productFieldSchemaCache = ProductFieldRepository::getProductFields(false)->toProductFieldSchema();
		}

return self::$productFieldSchemaCache;
	}

	public static function getProductSchema() {
		if (!self::$productSchemaCache) {
			self::$productSchemaCache = ProductFieldRepository::getProductFields(false)->toProductSchema();
		}

return self::$productSchemaCache;
	}

	private static function getACFFields(array $acfFieldGroups) {
		$groupedFields = [];
		foreach ($acfFieldGroups as $group) {
			$stringKeyedFields = [];
			foreach ($group->fields as $acfField) {
				$type = self::determineACFFieldType($acfField);
				$fieldId = (string) $acfField->id;
				$stringKeyedFields[$fieldId] = new ACFField(choices: $acfField->choices, fieldKey: $acfField->key, id: $acfField->id, label: $acfField->label, multiple: $acfField->multiple, name: $acfField->name, type: $type, acfType: $acfField->type);
			} $fieldsParam = $stringKeyedFields;
			$groupedFields[$group->id] = new ACFGroupedFields(groupId: $group->id, groupName: $group->name, fields: $fieldsParam);
		}

return new ACFFieldGroup($groupedFields);
	}

	private static function determineACFFieldType(ACFFieldData $acfField) {
		switch ($acfField->type) {
			case 'text': case 'textarea': case 'wysiwyg': case 'url': case 'email': return ProductFieldType::TEXT;
			case 'number': return ProductFieldType::INTEGER;
			case 'select': case 'radio': if ($acfField->multiple) {
				return ProductFieldType::MULTISELECT;
			}

return ProductFieldType::SELECT;
			case 'checkbox': return ProductFieldType::MULTISELECT;
			case 'true_false': return ProductFieldType::BOOLEAN;
			default: if ($acfField->choices) {
				return $acfField->multiple ? ProductFieldType::MULTISELECT : ProductFieldType::SELECT;
			}

return ProductFieldType::TEXT;
		}
	}

	private static function getBasicFields() {
		return new BasicFieldGroup([BasicFieldKeys::ID->value => new BasicField(type: ProductFieldType::POSITIVE_INTEGER, key: BasicFieldKeys::ID, editable: false, nullable: false), BasicFieldKeys::PARENT_ID->value => new BasicField(type: ProductFieldType::POSITIVE_INTEGER, key: BasicFieldKeys::PARENT_ID, editable: false, nullable: false), BasicFieldKeys::NAME->value => new BasicField(type: ProductFieldType::TEXT, key: BasicFieldKeys::NAME, editable: true, nullable: false), BasicFieldKeys::DESCRIPTION_LONG->value => new BasicField(type: ProductFieldType::TEXT, key: BasicFieldKeys::DESCRIPTION_LONG, editable: true, nullable: false), BasicFieldKeys::DESCRIPTION_SHORT->value => new BasicField(type: ProductFieldType::TEXT, key: BasicFieldKeys::DESCRIPTION_SHORT, editable: true, nullable: false), BasicFieldKeys::IMAGE_ID->value => new BasicField(type: ProductFieldType::POSITIVE_INTEGER, key: BasicFieldKeys::IMAGE_ID, editable: true, nullable: true), BasicFieldKeys::GALLERY_IMAGE_IDS->value => new BasicField(type: ProductFieldType::SELECT, key: BasicFieldKeys::GALLERY_IMAGE_IDS, editable: true, nullable: false), BasicFieldKeys::POST_STATUS->value => new BasicField(key: BasicFieldKeys::POST_STATUS, type: ProductFieldType::SELECT, options: ProductAPI::validPostStatuses, editable: true, nullable: false), BasicFieldKeys::SKU->value => new BasicField(type: ProductFieldType::TEXT, key: BasicFieldKeys::SKU, editable: true, nullable: false), BasicFieldKeys::REGULAR_PRICE->value => new BasicField(type: ProductFieldType::CURRENCY, key: BasicFieldKeys::REGULAR_PRICE, editable: true, nullable: true), BasicFieldKeys::SALE_PRICE->value => new BasicField(type: ProductFieldType::CURRENCY, key: BasicFieldKeys::SALE_PRICE, editable: true, nullable: true), BasicFieldKeys::STOCK_COUNT->value => new BasicField(type: ProductFieldType::INTEGER, key: BasicFieldKeys::STOCK_COUNT, editable: true, nullable: true), BasicFieldKeys::STOCK_STATUS->value => new BasicField(type: ProductFieldType::SELECT, key: BasicFieldKeys::STOCK_STATUS, options: ProductAPI::validStockStatuses, editable: true, nullable: true), BasicFieldKeys::TAX_CLASS->value => new BasicField(type: ProductFieldType::TEXT, key: BasicFieldKeys::TAX_CLASS, editable: true, nullable: true), BasicFieldKeys::TAX_STATUS->value => new BasicField(key: BasicFieldKeys::TAX_STATUS, type: ProductFieldType::SELECT, options: ProductAPI::validTaxStatuses, editable: true, nullable: true), BasicFieldKeys::TOTAL_SALES->value => new BasicField(key: BasicFieldKeys::TOTAL_SALES, type: ProductFieldType::INTEGER, editable: false, nullable: false)]);
	}

	private static function getCustomMetaFields() {
		if (!defined('SHOP_MANAGER_PRO_COMMERCIAL') || !SHOP_MANAGER_PRO_COMMERCIAL) {
			return new CustomMetaGroup([]);
		}

return \ShopManagerPro\Premium\CustomFields\CustomFieldDiscoveryService::getActiveCustomFieldsAsFieldDTO();
	}

	private static function getDefaultTaxonomies(array $taxonomies) {
		$fields = [];
		foreach ($taxonomies as $taxonomy) {
			if (!self::isDefaultTaxonomy($taxonomy->key)) {
				continue;
			} $values = [];
			foreach ($taxonomy->terms as $term) {
				$values[] = new DefaultTaxonomyValue(id: $term->id, name: $term->name);
			} $fields[] = new DefaultTaxonomyField(key: $taxonomy->key, name: $taxonomy->name, terms: $values);
		}

return new DefaultTaxonomyFieldGroup($fields);
	}

	private static function getProductAttributes(array $taxonomies) {
		$fields = [];
		foreach ($taxonomies as $taxonomy) {
			if (!self::isProductAttribute($taxonomy->key)) {
				continue;
			} $values = [];
			foreach ($taxonomy->terms as $term) {
				$values[] = new ProductAttributeValue(id: $term->id, name: $term->name);
			} $fields[] = new ProductAttributeField(key: $taxonomy->key, name: $taxonomy->name, terms: $values);
		}

return new ProductAttributeFieldGroup($fields);
	}

	private static function getACFFieldData() {
		if (!self::$acfFields) {
			self::$acfFields = \ShopManagerPro\ACF\ACFRepository::getACFFields()->acfFieldGroups;
		}

return self::$acfFields;
	}

	private static function getTaxonomyData() {
		if (!self::$taxonomies) {
			self::$taxonomies = TaxonomyRepository::getTaxonomies()->taxonomiesByKey;
		}

return self::$taxonomies;
	}

	public static function isDefaultTaxonomy(string $taxonomyKey) {
		return !self::isProductAttribute($taxonomyKey);
	}

	public static function isProductAttribute(string $taxonomyKey) {
		return str_starts_with($taxonomyKey, 'pa_');
	}
}
