<?php

// If this file is called directly, abort.
if (! defined('ABSPATH')) {
	exit;
}

class PostsCategoriesController {

	private $termCache = [];

	public function getCategories() {
		$postTypes = get_post_types(['public' => true,]);
		$exclude = ['page', 'attachment', 'revision', 'nav_menu_item', 'product'];
		$postTypes = array_diff($postTypes, $exclude);

		if (!in_array('post', $postTypes, true)) {
			$postTypes[] = 'post';
		}

		$allTaxonomies = [];
		foreach ($postTypes as $postType) {
			$taxonomies = get_object_taxonomies($postType, 'objects');
			foreach ($taxonomies as $name => $taxonomy) {
				if ($taxonomy->hierarchical) {
					$allTaxonomies[$name] = $taxonomy;
				}
			}
		}

		$result = [];

		foreach ($allTaxonomies as $taxonomy) {
			$terms = get_terms([
				'taxonomy' => $taxonomy->name,
				'hide_empty' => false,
			]);

			if (is_wp_error($terms) || empty($terms)) {
				continue;
			}

			foreach ($terms as $term) {
				$this->termCache[$term->term_id] = $term;
			}

			foreach ($terms as $term) {
				$parentName = '';
				if ($term->parent && isset($this->termCache[$term->parent])) {
					$parentName = $this->termCache[$term->parent]->name;
				}

				$imageId = get_term_meta($term->term_id, 'thumbnail_id', true);
				$image = $imageId ? wp_get_attachment_url($imageId) : '';

				$result[] = [
					'id' => (int) $term->term_id,
					'name' => $term->name ?? "",
					'url' => esc_url(get_term_link($term)),
					'image' => $image ?? null,
					'parent_id' => $term->parent > 0 ? $term->parent : 0,
					'parent_name' => $parentName ?? '',
					'level' => $this->getLevel($term),
					'path' => $this->buildPath($term),
					'category_size' => $term->count
				];
			}
		}
		return $result;
	}

	private function buildPath($term) {
		$segments = [];
		$current = $term;

		while ($current->parent) {
			if (!isset($this->termCache[$current->parent])) break;
			$parent = $this->termCache[$current->parent];
			array_unshift($segments, $parent->name);
			$current = $parent;
		}

		$segments[] = $term->name;
		return implode(' > ', $segments);
	}

	private function getLevel($term) {
		$level = 2;
		$current = $term;

		while ($current->parent) {
			if (!isset($this->termCache[$current->parent])) break;
			$current = $this->termCache[$current->parent];
			$level++;
		}

		return $level;
	}
}