<?php

namespace MenuManagerUltra\lib\MenuItem;

use MenuManagerUltra\lib\Post\PostDataFormatter;
use MenuManagerUltra\lib\Term\TermDataFormatter;

class MenuItemFormatter {

  public const MENU_ITEM_OBJECT_TYPE_CUSTOM = 'custom';
  public const MENU_ITEM_TYPE_POST = 'post_type';
  public const MENU_ITEM_TYPE_TAXONOMY = 'taxonomy';

  public static $menu_items_by_parent = [];

  public static function applyLinks($menu_item) {

    try {
      if (!$menu_item) {
        throw new \InvalidArgumentException("Invalid menu item");
      }
    
      if (!empty($menu_item->type)) {
        if ($menu_item->type != self::MENU_ITEM_OBJECT_TYPE_CUSTOM) {

          if ($menu_item->type == self::MENU_ITEM_TYPE_POST) {
            $menu_item = PostDataFormatter::applyLinks($menu_item->object_id, $menu_item);
          }
          else if ($menu_item->type == self::MENU_ITEM_TYPE_TAXONOMY) {
            $menu_item = TermDataFormatter::applyLinks($menu_item->object_id, $menu_item);
          }

        }
        else {
          $menu_item->display_link = $menu_item->url;
          $menu_item->goto_link = $menu_item->url;
        }
      }
    }
    catch(\Exception $e) {
      // @TODO error log here, but don't die.
    }
  
    return $menu_item;
  }

  public static function applyDefaultFields($menu_item) {

    if (!$menu_item) {
      throw new \InvalidArgumentException("Invalid menu item");
    }
  
    if ($menu_item->object != self::MENU_ITEM_OBJECT_TYPE_CUSTOM) {
      if (!empty($menu_item->object_id)) {

        if ($menu_item->type == self::MENU_ITEM_TYPE_TAXONOMY) {
          $menu_item->object_title = get_term_field('name', $menu_item->object_id);
        }
        else {
          $menu_item->object_title = get_post_field('post_title', $menu_item->object_id);
        }
      }
    }
    
    return $menu_item;
  }

  public static function applyCustomFields($menu_item) {

    $enabled_custom_fields = get_option('mmu_custom_fields_applied', []);
    $menu_item->object_fields = [];
  
    foreach ($enabled_custom_fields as $info) {
      try {
        if ($field_obj = \MenuManagerUltra\lib\CustomField\CustomFieldManager::create($info['field_source'])) {
          if (!empty($menu_item->object_id)) {
  
            $field_info = $field_obj->info($info['field_key']);
            $field_arr  = $field_info->asArray();
            $field_arr['field_value'] = $field_obj->value($info['field_key'], $menu_item->object_id);
  
            $menu_item->object_fields[] = $field_arr;
            
          }
        }
      }
      catch(\Exception $e) {
        // @TODO: Log this error. It shouldn't bomb if the field source is no longer valid for some reason.
      }
    }
  
    return $menu_item;
  
  }

  public static function getMenuItemsByParent($menu_id, $force_refresh = false) {
    
    self::confirmValidMenuID($menu_id);
    
    // Load menu items into the cache only if this menu_id hasn't been processed yet
    if ($force_refresh || !isset(static::$menu_items_by_parent[$menu_id])) {
        // Fetch all menu items for the given menu_id
        $args = [
            'post_type'      => 'nav_menu_item',
            'posts_per_page' => -1,
            'fields'         => 'ids', // Fetch only IDs for performance
            'cache_results'  => false,
            'tax_query'      => [
                [
                    'taxonomy' => 'nav_menu',
                    'field'    => 'term_taxonomy_id',
                    'terms'    => $menu_id
                ]
            ]
        ];

        $all_menu_items = get_posts($args);

        // Organize items by their parent_id for quick lookup
        static::$menu_items_by_parent[$menu_id] = [];
        foreach ($all_menu_items as $item) {
            $parent_id = get_post_meta($item, '_menu_item_menu_item_parent', true);
            static::$menu_items_by_parent[$menu_id][$parent_id][] = $item;
        }
    }

    return static::$menu_items_by_parent;
  }

  public static function applyChildDataToItems($items_arr, $menu_id, $force_refresh = false) {

    $updated_items = [];
    
    self::confirmValidMenuID($menu_id);
    
    $menu_items_by_parent = static::getMenuItemsByParent($menu_id, $force_refresh);
    
    $updated_items = array_map(
      function($menu_item) use ($menu_items_by_parent, $menu_id) {
        $item_id = (is_object($menu_item)) ? $menu_item->ID : $menu_item['ID'];

        // Determine the number of children efficiently using our cache
        $children_count = isset($menu_items_by_parent[$menu_id][$item_id]) 
            ? count($menu_items_by_parent[$menu_id][$item_id]) 
            : 0;
    
        // Store the result in the object or array
        if (is_object($menu_item)) {
          $menu_item->has_fetchable_children = $children_count;
        } 
        else {
          $menu_item['has_fetchable_children'] = $children_count;
        }

        return $menu_item;
      },
      $items_arr
    );

    return $updated_items;

  }

  public static function applyChildDataToItem($menu_item, $menu_id, $force_refresh = false) {

    self::confirmValidMenuItem($menu_item);
    self::confirmValidMenuID($menu_id);
    
    $menu_items_by_parent = static::getMenuItemsByParent($menu_id, $force_refresh);
    
    $item_id = (is_object($menu_item)) ? $menu_item->ID : $menu_item['ID'];

    $children_count = isset($menu_items_by_parent[$menu_id][$item_id]) 
        ? count($menu_items_by_parent[$menu_id][$item_id]) 
        : 0;

    // Store the result in the object or array
    if (is_object($menu_item)) {
      $menu_item->has_fetchable_children = $children_count;
    } 
    else {
      $menu_item['has_fetchable_children'] = $children_count;
    }

    return $menu_item;
  }  

  public static function applyChildDataToItemFromDb($menu_item, $menu_id = null) {

    if ($menu_id !== null) {
      self::confirmValidMenuID($menu_id);
    }

    self::confirmValidMenuItem($menu_item);

    $item_id = (is_object($menu_item)) ? $menu_item->ID : $menu_item['ID'];
    
    $tax_query = [];

    if ($menu_id) {
      $tax_query = array(
        array(
          'taxonomy' => 'nav_menu',
          'field'    => 'term_taxonomy_id',
          'terms'    => $menu_id
        )
      );
    }

    $child_query = new \WP_Query([
      'post_type' => 'nav_menu_item',
      'posts_per_page' => -1,
      'fields' => 'ids',
      'meta_query' => [
        [
        'key' => '_menu_item_menu_item_parent',
        'value' => $item_id
        ]
      ],
      'tax_query' => $tax_query,
    ]);
  
    $children_count = ($child_query->found_posts) ? $child_query->found_posts : 0;

    if (is_object($menu_item)) {
      $menu_item->has_fetchable_children = $children_count;
    }
    else {
      $menu_item['has_fetchable_children'] = $children_count;
    }
    
  
    return $menu_item;
  }

  public static function confirmValidMenuID($menu_id) {
    
    if (!$menu_id || !is_numeric($menu_id)) {
      throw new \InvalidArgumentException("Invalid Menu ID");
    }
  }
  
  public static function confirmValidMenuItem($menu_item) {
    if (!$menu_item) {
      throw new \InvalidArgumentException("No Menu Item Found");
    }
    
    $menu_item = (array) $menu_item;
  
    if (empty($menu_item['ID'])) {
      throw new \InvalidArgumentException("No ID found for Menu Item");
    }
  
    return true;
  }

}
