<?php
require_once 'productMain.php';

class ProductDetails {

  protected PDO $pdo;
  protected string $language;
  protected ProductMain $main;  

  protected array $activeOptions = [];
  protected array $allGroups = [];
  protected array $allGroupsBySlug = [];
  protected array $allItems = [];
  protected array $allItemsByGroupSlug = [];
  protected array $input = [];
  
  
  protected ?int $pricingCountry = null;
  protected int $pricingQuantity = 1;
  protected ?int $fallbackCountry = null;
  
  protected string $currencyCode   = 'EUR';
  protected string $currencyLocale = 'de';
  protected int    $currencyDecimals = 2;
  
  protected ?string $attributeVisibilityColumn = 'c_details';
  
  protected int $id;
	protected int $originalId;
	
	protected bool $catalogLoaded = false;
	
	protected bool $onlyChecked = false;
	protected array $onlyCheckedTypes = ['properties'];

  public function setConnection(PDO $conn): void {
    global $language;
    $this->language = $language;
    $this->pdo = $conn;
    $this->main = new ProductMain($conn, $this->language);
    $this->main->setCurrency($this->currencyCode, $this->currencyLocale, $this->currencyDecimals);
	  $this->main->setPricingContext($this->pricingCountry, $this->pricingQuantity);
	  $this->main->setPricingFallbackCountry($this->fallbackCountry);
  }
  
  public function setCurrency(string $code = 'EUR', string $locale = 'de', int $dec = 2): void {
    $this->currencyCode = $code; $this->currencyLocale = $locale; $this->currencyDecimals = $dec;
    if (isset($this->main)) $this->main->setCurrency($code, $locale, $dec);
  }
  
  public function setPricingContext(?int $id_country, int $quantity = 1): void {
    $this->pricingCountry  = $id_country;
    $this->pricingQuantity = max(1, (int)$quantity);
    if (isset($this->main)) $this->main->setPricingContext($id_country, $quantity);
  }

  public function setPricingFallbackCountry(?int $id_country): void {
    $this->fallbackCountry = $id_country;
    if (isset($this->main)) $this->main->setPricingFallbackCountry($id_country);
  }
  
  protected function ensureCatalogLoaded(): void {
	  if ($this->catalogLoaded) return;
	  $this->allGroups = [];
	  $this->allGroupsBySlug = [];
	  $this->allItems = [];
	  $this->allItemsByGroupSlug = [];
	  
	  $this->loadGroups('tags');
	  $this->loadGroups('properties');
	  $this->loadItems('tags');
	  $this->loadItems('properties');
	  $this->catalogLoaded = true;
	}


  public function setInput(array $input): void {
    $this->input = $input;
    
    $this->activeOptions = [];

	  $this->originalId = isset($input['id']) ? (int)$input['id'] : 0;
	  $this->id = $this->originalId;
	
	  $this->ensureCatalogLoaded();
	
	  $this->loadActiveOptionsFromSlugs();
	
	  $targetId = $this->main->getParentId($this->originalId) ?: $this->originalId;
	  
	  $variantId = $this->findMatchingVariantId($targetId);
		if ($variantId && $variantId != $this->originalId) {
		  $this->id = $variantId;
		}
  }
  
  public function setAttributeVisibility(string $context): void {
	  $map = [
	    'details' => 'c_details',
	    'cart'    => 'c_cart',
	    'order'   => null,
	  ];
	
	  if (!array_key_exists($context, $map)) {
	    throw new InvalidArgumentException('Invalid attribute visibility context: '.$context);
	  }
	
	  $this->attributeVisibilityColumn = $map[$context];
	
	  $this->catalogLoaded = false;
	  $this->allGroups = [];
	  $this->allGroupsBySlug = [];
	  $this->allItems = [];
	  $this->allItemsByGroupSlug = [];
	}

  public function getId(): int {
    return $this->id;
  }
  
  public function onlyCheckedAttributes(bool $enabled = true, array $types = ['properties']): void {
	  $this->onlyChecked = $enabled;
	  $this->onlyCheckedTypes = $types ?: ['properties', 'tags'];
	}

  public function getDisplayData(): array {
  	[$id_country, $quantity, $fallbackCountry] = [$this->pricingCountry, $this->pricingQuantity, $this->fallbackCountry];

    $isVariant = $this->main->isVariant($this->id);
		$hasVariants = $this->main->hasVariants($this->id);
		if ($isVariant || !$hasVariants) {
		  $price = [
		    'mode' => 'single',
		    'data' => $this->main->getPriceSingle($this->id, $id_country, $quantity, $fallbackCountry)
		  ];
		} else {
		  $price = [
		    'mode' => 'summary',
		    'data' => $this->main->getPriceSummary($this->id, $id_country, $quantity, $fallbackCountry)
		  ];
		}

		$parentId = $this->main->getParentId($this->id);
	  $content  = $isVariant ? $this->main->getMergedContent($this->id, $parentId) : $this->main->getContent($this->id, $this->language, true);
	  
	  $stock = $this->main->getStockStatus($this->id);
		
		if ($this->id === $parentId) {
		  $stock = $this->main->getBestVariantStockStatus($parentId);
		}
	  
  	$canAdd = $this->main->canAddToCart($this->id, $this->pricingQuantity);
  	
    return [
      'content'     		=> $content,
      'images'      		=> $this->main->getImages($this->id, true),
      'files'       		=> $this->main->getFiles($this->id, true),
      'weight'       		=> $this->main->getWeight($this->id, true),
      'attributes'  		=> $this->getDisplayAttributes(),
      'price'       		=> $price,
      'sku'         		=> $this->main->getSku($this->id),
      'stock'       		=> $stock,
	    'can_add_to_cart' => $canAdd,
	    'delivery_hint'   => $this->main->deliveryHintFromStock($stock),
    ];
  }
	
  protected function getDisplayAttributes(): array {
	  $parentId   = $this->main->getParentId($this->id);
	  $isVariant  = $this->main->isVariant($this->id);
	  $hasActive  = !empty($this->activeOptions);
    
    
    $parentPropIx = $this->linksIndexByGroup($this->getLinksByType($parentId, 'properties'));
	  $parentTagIx  = $this->linksIndexByGroup($this->getLinksByType($parentId, 'tags'));
	
	  $variantPropIx = $isVariant ? $this->linksIndexByGroup($this->getLinksByType($this->id, 'properties')) : [];
	  $variantTagIx  = $isVariant ? $this->linksIndexByGroup($this->getLinksByType($this->id, 'tags')) : [];

    $output = ['tags' => [], 'properties' => []];
    foreach ($this->allGroups as $group_key => $group_value) {
      $type = $group_value['type'];
      $slug  = $group_value['url'] ?? '';
      $items = $this->allItems[$group_key] ?? [];
      if (!$items) continue;
      
      $allowedSet = [];
	    if ($type === 'properties') {
	      $allowedSet = $parentPropIx[$group_key] ?? [];
	    } else {
	      if (!empty($variantTagIx[$group_key])) {
	        $allowedSet = $variantTagIx[$group_key];
	      } else {
	        $allowedSet = $parentTagIx[$group_key] ?? [];
	      }
	    }
	    
	    if (empty($allowedSet)) continue;

			$values = [];
      foreach ($items as $item) {
        if (!isset($allowedSet[$item['guidv4']])) continue;
        
        $checked = false;        
	      if ($isVariant) {
	        if ($type === 'properties' && isset($variantPropIx[$group_key][$item['guidv4']])) $checked = true;
	      }
	      if (!$checked && $hasActive && in_array($item['guidv4'], $this->activeOptions[$group_key] ?? [], true)) {
	        $checked = true;
	      }
	      
	      if ($this->onlyChecked && in_array($type, $this->onlyCheckedTypes, true) && !$checked) {
			    continue;
			  }

        $values[] = [
          'title'     => $item['title'],
          'checked'   => $checked,
          'guidv4'    => $item['guidv4'],
          'class'     => $item['class'],
          'url'       => $item['url'] ?? null,
          'id_media'  => $item['id_media'] ?? [],
        ];
      }

      if (!empty($values)) {
        $output[$type][$group_key] = [
          'title' 			=> $group_value['title'],
          'url' 				=> $group_value['url'],
          'field_type'	=> $group_value['field_type'],
          'class'				=> $group_value['class'],
          'values' 			=> $values,
        ];
      }
    }
    return $output;
  }
  
  protected function getLinksByType(int $id, string $type): array {
	  $sql = "SELECT guidv4, guidv4_group FROM products_product_".$type."_links WHERE id_module = :id_module";
	  $result = $this->pdo->prepare($sql);
	  $result->bindValue(':id_module', $id, PDO::PARAM_INT);
	  $result->execute();
	  $links = [];
	  while ($arr = $result->fetch(PDO::FETCH_ASSOC)) {
	    $links[] = $arr;
	  }
	  return $links;
	}
	
	protected function linksIndexByGroup(array $arr): array {
	  $ix = [];
	  foreach ($arr AS $r) {
	    $g = $r['guidv4_group'] ?? null;
	    $v = $r['guidv4'] ?? null;
	    if (!$g || !$v) continue;
	    $ix[$g][$v] = true;
	  }
	  return $ix;
	}

  protected function getProductLinks(int $id): array {
    $links = [];
    foreach (["tags", "properties"] as $type) {
      $sql = "SELECT guidv4 FROM products_product_".$type."_links WHERE id_module = :id_module";
      $result = $this->pdo->prepare($sql);
      $result->bindValue(':id_module', $id);
      $result->execute();
      while ($arr = $result->fetch()) $links[] = $arr['guidv4'];
    }
    return $links;
  }

  protected function loadActiveOptionsFromSlugs(): void {
    $input = $this->input ?? $_GET;
    foreach ($input as $key => $value) {
      foreach (["tags", "properties"] as $type) {
        $prefix = $type . '_';
        if (strpos($key, $prefix) === 0) {
          $groupSlug = substr($key, strlen($prefix));
          $itemSlugs = is_array($value) ? $value : explode(',', $value);
          if (!isset($this->allGroupsBySlug[$type][$groupSlug])) continue;
          $groupId = $this->allGroupsBySlug[$type][$groupSlug]['guidv4'];
          $itemsInGroup = $this->allItemsByGroupSlug[$type][$groupSlug] ?? [];
          foreach ($itemSlugs as $slug) {
            $slug = trim($slug);
            if (isset($itemsInGroup[$slug])) {
              $this->activeOptions[$groupId][] = $itemsInGroup[$slug]['guidv4'];
            }
          }
        }
      }
    }
  }

  public function findMatchingVariantId(int $mainProductId): ?int {
    $selected = $this->getSelectedProperties();
    if (empty($selected)) return null;

    $sql = "SELECT products.id, products_product_properties_links.guidv4, products_product_properties_links.guidv4_group
            FROM products AS products
            LEFT JOIN products_product_properties_links AS products_product_properties_links ON products_product_properties_links.id_module = products.id
            WHERE products.id_module = :id_module";
    $result = $this->pdo->prepare($sql);
    $result->bindValue(':id_module', $mainProductId, PDO::PARAM_INT);
    $result->execute();

    $variants = [];
    $valuesPerGroup = [];
    while ($arr = $result->fetch()) {
	    if ($arr['guidv4_group'] && $arr['guidv4']) {
	      $variants[$arr['id']][$arr['guidv4_group']] = $arr['guidv4'];
	      $valuesPerGroup[$arr['guidv4_group']][$arr['guidv4']] = true;
	    }
	  }
	  if (empty($variants)) return null;
	  
	  if (count($variants) === 1) {
	    return (int) array_key_first($variants);
	  }

    $requiredGroups = [];
	  foreach ($valuesPerGroup AS $group => $value) {
	    if (count($value) > 1) {
	      $requiredGroups[$group] = true;
	    }
	  }
	  
	  if (empty($requiredGroups)) {
		  $candidates = [];
		  foreach ($variants as $variantId => $props) {
		    $ok = true;
		    foreach ($selected as $g => $v) {
		      if (!isset($props[$g]) || $props[$g] !== $v) { $ok = false; break; }
		    }
		    if ($ok) $candidates[] = (int)$variantId;
		  }
		  if (count($candidates) === 1) return $candidates[0];
		  return null;
		}
			
	  foreach (array_keys($requiredGroups) AS $group) {
	    if (!isset($selected[$group])) {
	      return null;
	    }
	  }
	
	  foreach ($variants AS $variantId => $props) {
	    $ok = true;
	    foreach (array_keys($requiredGroups) AS $group) {
	      if (!isset($props[$group]) || $props[$group] !== $selected[$group]) {
	        $ok = false; break;
	      }
	    }
	    if ($ok) return (int)$variantId;
	  }
	
	  return null;
  }

  public function getSelectedProperties(): array {
    $selected = [];
    foreach ($this->activeOptions as $groupGuid => $guids) {
      if (!empty($guids)) {
        $selected[$groupGuid] = $guids[0];
      }
    }
    return $selected;
  }

  protected function loadGroups(string $type): void {
  	if (!in_array($type, ['tags', 'properties'], true)) {
	    throw new InvalidArgumentException('Invalid attribute type: '.$type);
	  }
	  
    $images = [];
    $sql = "SELECT id_module, id_media FROM products_".$type."_groups_images ORDER BY sortorder ASC";
    $result = $this->pdo->prepare($sql);
    $result->execute();
    while ($arr = $result->fetch()) $images[$arr['id_module']] = $arr['id_media'];

    $sql = "SELECT * FROM products_".$type."_groups WHERE c_active = '1' AND ";
    if ($this->attributeVisibilityColumn !== null) {
    	$sql .= $this->attributeVisibilityColumn." = '1' AND ";
    }
    $sql .= "language = :language ORDER BY sortorder ASC";
    $result = $this->pdo->prepare($sql);
    $result->bindValue(':language', $this->language, PDO::PARAM_STR);
    $result->execute();
    while ($arr = $result->fetch()) {
      if (isset($images[$arr['id']])) $arr['id_media'] = $images[$arr['id']];
      $arr['type'] = $type;
      $this->allGroups[$arr['guidv4']] = $arr;
      if (!empty($arr['url'])) {
        $this->allGroupsBySlug[$type][$arr['url']] = $arr;
      }
    }
  }

  protected function loadItems(string $type): void {
    $images = [];
    $sql = "SELECT id_module, id_media FROM products_".$type."_images ORDER BY sortorder ASC";
    $result = $this->pdo->prepare($sql);
    $result->execute();
    while ($arr = $result->fetch()) $images[$arr['id_module']][] = $arr['id_media'];

    $sql = "SELECT * FROM products_".$type." WHERE c_active = '1' AND language = :language ORDER BY sortorder ASC";
    $result = $this->pdo->prepare($sql);
    $result->bindValue(':language', $this->language, PDO::PARAM_STR);
    $result->execute();
    while ($arr = $result->fetch()) {
      if (isset($images[$arr['id']])) $arr['id_media'] = $images[$arr['id']];
      $group = $this->allGroups[$arr['guidv4_group']] ?? null;
      if (!$group) continue;
      $type = $group['type'];
      $groupSlug = $group['url'];
      $this->allItems[$arr['guidv4_group']][] = $arr;
      if (!empty($arr['url'])) {
        $this->allItemsByGroupSlug[$type][$groupSlug][$arr['url']] = $arr;
      }
    }
  }
}
