<?php
/**
 * Categories REST controller.
 *
 * @package JOCBM
 */

namespace JOCBM\Rest;

use JOCBM\Database\Schema;
use JOCBM\Services\TemplateLibrary;
use WP_REST_Response;
use WP_REST_Server;

defined( 'ABSPATH' ) || exit;

/**
 * Class CategoriesController
 */
final class CategoriesController {

	use RestPermissions;

	/**
	 * Register routes.
	 */
	public function register_routes(): void {
		register_rest_route(
			RestApi::NAMESPACE,
			'/categories',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'index' ),
				'permission_callback' => array( $this, 'can_manage' ),
			)
		);
	}

	/**
	 * List categories with block counts (flat + tree).
	 */
	public function index(): WP_REST_Response {
		global $wpdb;

		$cats   = Schema::table( 'categories' );
		$blocks = Schema::table( 'system_blocks' );
		$junction = Schema::table( 'system_block_categories' );

		// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber -- %i table identifiers are not counted by PHPCS.
		$rows = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT c.*, COUNT(DISTINCT b.id) AS block_count
			FROM %i c
			LEFT JOIN %i j ON j.category_id = c.id
			LEFT JOIN %i b ON b.id = j.system_block_id AND b.is_active = 1
			GROUP BY c.id
			ORDER BY
				CASE WHEN c.parent_slug = '' THEN 0 ELSE 1 END ASC,
				c.sort_order ASC,
				c.name ASC",
				$cats,
				$junction,
				$blocks
			),
			ARRAY_A
		);

		$featured_count = (int) $wpdb->get_var(
			$wpdb->prepare(
				'SELECT COUNT(*) FROM %i WHERE is_active = 1 AND is_featured = 1',
				$blocks
			)
		);

		$items = array();
		foreach ( $rows ?: array() as $row ) {
			$items[] = array(
				'id'          => (int) $row['id'],
				'slug'        => $row['slug'],
				'name'        => $row['name'],
				'description' => $row['description'],
				'parentSlug'  => (string) ( $row['parent_slug'] ?? '' ),
				'isPro'       => ! empty( $row['is_pro'] ),
				'sortOrder'   => (int) $row['sort_order'],
				'blockCount'  => (int) $row['block_count'],
			);
		}

		// Owner packs are file-first — bump leaf counts from disk (ready only).
		$owner_by_cat = array();
		$owner_featured = 0;
		foreach ( TemplateLibrary::ready_owner_blocks() as $pack ) {
			$pack_slugs = is_array( $pack['categories'] ?? null )
				? $pack['categories']
				: array( (string) ( $pack['category'] ?? '' ) );
			$seen_pack = array();
			foreach ( $pack_slugs as $cat ) {
				$cat = sanitize_key( (string) $cat );
				if ( '' === $cat || isset( $seen_pack[ $cat ] ) ) {
					continue;
				}
				$seen_pack[ $cat ] = true;
				$owner_by_cat[ $cat ] = ( $owner_by_cat[ $cat ] ?? 0 ) + 1;
			}
			if ( ! empty( $pack['is_featured'] ) ) {
				++$owner_featured;
			}
		}
		foreach ( $items as &$item ) {
			if ( isset( $owner_by_cat[ $item['slug'] ] ) ) {
				$item['blockCount'] += $owner_by_cat[ $item['slug'] ];
			}
		}
		unset( $item );

		// Parent group counts = sum of leaf children.
		$by_parent = array();
		foreach ( $items as $item ) {
			if ( $item['parentSlug'] ) {
				$by_parent[ $item['parentSlug'] ] = ( $by_parent[ $item['parentSlug'] ] ?? 0 ) + $item['blockCount'];
			}
		}
		foreach ( $items as &$item ) {
			if ( '' === $item['parentSlug'] && isset( $by_parent[ $item['slug'] ] ) ) {
				$item['blockCount'] = $by_parent[ $item['slug'] ];
			}
		}
		unset( $item );

		$featured_count += $owner_featured;

		$tree = self::build_tree( $items );

		return new WP_REST_Response(
			array(
				'items'         => $items,
				'tree'          => $tree,
				'featuredCount' => $featured_count,
			),
			200
		);
	}

	/**
	 * Nest flat categories under parents.
	 *
	 * @param array<int, array<string, mixed>> $items Flat categories.
	 * @return array<int, array<string, mixed>>
	 */
	private static function build_tree( array $items ): array {
		$children = array();
		$roots    = array();

		foreach ( $items as $item ) {
			$parent = $item['parentSlug'] ?? '';
			if ( $parent ) {
				$children[ $parent ][] = $item;
			} else {
				$roots[] = $item;
			}
		}

		foreach ( $roots as &$root ) {
			$root['children'] = $children[ $root['slug'] ] ?? array();
		}
		unset( $root );

		return $roots;
	}
}
