<?php

/**
 * TaxonomyHandler — Domain handler for taxonomy term read/write actions.
 *
 * Owns: get_taxonomies, manage_taxonomies
 *
 * @package LolaCore\Actions\Handlers
 * @license GPL-2.0-or-later
 */

declare( strict_types=1 );

namespace LolaCore\Actions\Handlers;

use LolaCore\Actions\Contracts\ActionHandlerInterface;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Handles get_taxonomies and manage_taxonomies actions.
 */
class TaxonomyHandler implements ActionHandlerInterface {

	/** @inheritDoc */
	public function getSupportedActions(): array {
		return array( 'get_taxonomies', 'manage_taxonomies' );
	}

	/** @inheritDoc */
	public function handle( string $actionId, array $params, bool $dryRun ): array {
		return match ( $actionId ) {
			'get_taxonomies'    => $this->getTaxonomies( $params ),
			'manage_taxonomies' => $this->manageTaxonomies( $params, $dryRun ),
			default             => throw new \Exception( esc_html( "TaxonomyHandler: unknown action '{$actionId}'." ) ),
		};
	}

	/**
	 * Lists all public taxonomies or the terms within a specific taxonomy.
	 *
	 * @param array $params Expects: taxonomy (string, optional), hide_empty (bool, optional).
	 * @return array
	 * @throws \Exception On WP_Error from get_terms().
	 */
	private function getTaxonomies( array $params ): array {
		$taxonomy   = $params['taxonomy'] ?? '';
		$hide_empty = isset( $params['hide_empty'] ) ? (bool) $params['hide_empty'] : true;

		if ( ! empty( $taxonomy ) ) {
			$terms = get_terms( array(
				'taxonomy'   => $taxonomy,
				'hide_empty' => $hide_empty,
			) );

			if ( is_wp_error( $terms ) ) {
				throw new \Exception( esc_html( $terms->get_error_message() ) );
			}

			$data = array();
			foreach ( $terms as $term ) {
				$data[] = array(
					'id'     => $term->term_id,
					'name'   => $term->name,
					'slug'   => $term->slug,
					'count'  => $term->count,
					'parent' => $term->parent,
				);
			}
			return array(
				'taxonomy' => $taxonomy,
				'terms'    => $data,
			);
		}

		// If no specific taxonomy, list all public taxonomies.
		$taxonomies = get_taxonomies( array( 'public' => true ), 'objects' );
		$data       = array();
		foreach ( $taxonomies as $tax ) {
			$data[] = array(
				'name'         => $tax->name,
				'label'        => $tax->label,
				'hierarchical' => $tax->hierarchical,
			);
		}
		return array( 'taxonomies' => $data );
	}

	/**
	 * Create, update, or delete a taxonomy term.
	 *
	 * @param array $params Expects: action (create|update|delete), taxonomy, name/slug/parent/term_id.
	 * @param bool  $dryRun If true, returns a preview without executing.
	 * @return array
	 * @throws \Exception On validation failure or WP_Error.
	 */
	private function manageTaxonomies( array $params, bool $dryRun ): array {
		$action   = $params['action'] ?? '';
		$taxonomy = $params['taxonomy'] ?? '';

		if ( ! in_array( $action, array( 'create', 'update', 'delete' ), true ) ) {
			throw new \Exception( "Invalid action. Use 'create', 'update', or 'delete'." );
		}
		if ( empty( $taxonomy ) || ! taxonomy_exists( $taxonomy ) ) {
			throw new \Exception( esc_html( "Taxonomy '{$taxonomy}' does not exist." ) );
		}

		if ( $action === 'create' ) {
			return $this->createTerm( $taxonomy, $params, $dryRun );
		}
		if ( $action === 'update' ) {
			return $this->updateTerm( $taxonomy, $params, $dryRun );
		}
		return $this->deleteTerm( $taxonomy, $params, $dryRun );
	}

	/**
	 * Create a new taxonomy term.
	 */
	private function createTerm( string $taxonomy, array $params, bool $dryRun ): array {
		$name   = $params['name'] ?? '';
		$slug   = $params['slug'] ?? '';
		$parent = isset( $params['parent'] ) ? (int) $params['parent'] : 0;

		if ( empty( $name ) ) {
			throw new \Exception( 'Term name is required for create.' );
		}

		if ( $dryRun ) {
			return array(
				'action'   => 'Will create taxonomy term',
				'taxonomy' => $taxonomy,
				'name'     => $name,
				'slug'     => $slug,
				'parent'   => $parent,
			);
		}

		$args = array();
		if ( ! empty( $slug ) ) {
			$args['slug'] = $slug;
		}
		if ( $parent > 0 ) {
			$args['parent'] = $parent;
		}

		$result = wp_insert_term( $name, $taxonomy, $args );
		if ( is_wp_error( $result ) ) {
			throw new \Exception( esc_html( $result->get_error_message() ) );
		}

		return array(
			'success'  => true,
			'term_id'  => $result['term_id'],
			'taxonomy' => $taxonomy,
			'message'  => "Term '{$name}' created in {$taxonomy}.",
		);
	}

	/**
	 * Update an existing taxonomy term.
	 */
	private function updateTerm( string $taxonomy, array $params, bool $dryRun ): array {
		$term_id = isset( $params['term_id'] ) ? (int) $params['term_id'] : 0;
		if ( $term_id <= 0 ) {
			throw new \Exception( 'term_id is required for update.' );
		}

		$term = get_term( $term_id, $taxonomy );
		if ( ! $term || is_wp_error( $term ) ) {
			throw new \Exception( esc_html( "Term ID {$term_id} not found in {$taxonomy}." ) );
		}

		$args = array();
		if ( isset( $params['name'] ) ) {
			$args['name'] = $params['name'];
		}
		if ( isset( $params['slug'] ) ) {
			$args['slug'] = $params['slug'];
		}
		if ( isset( $params['parent'] ) ) {
			$args['parent'] = (int) $params['parent'];
		}

		if ( empty( $args ) ) {
			throw new \Exception( 'Nothing to update.' );
		}

		if ( $dryRun ) {
			return array(
				'action'   => 'Will update taxonomy term',
				'taxonomy' => $taxonomy,
				'term_id'  => $term_id,
				'changes'  => $args,
			);
		}

		$result = wp_update_term( $term_id, $taxonomy, $args );
		if ( is_wp_error( $result ) ) {
			throw new \Exception( esc_html( $result->get_error_message() ) );
		}

		return array(
			'success'  => true,
			'term_id'  => $term_id,
			'taxonomy' => $taxonomy,
			'message'  => "Term ID {$term_id} updated.",
		);
	}

	/**
	 * Delete a taxonomy term.
	 */
	private function deleteTerm( string $taxonomy, array $params, bool $dryRun ): array {
		$term_id = isset( $params['term_id'] ) ? (int) $params['term_id'] : 0;
		if ( $term_id <= 0 ) {
			throw new \Exception( 'term_id is required for delete.' );
		}

		$term = get_term( $term_id, $taxonomy );
		if ( ! $term || is_wp_error( $term ) ) {
			throw new \Exception( esc_html( "Term ID {$term_id} not found in {$taxonomy}." ) );
		}

		if ( $dryRun ) {
			return array(
				'action'   => 'Will delete taxonomy term',
				'taxonomy' => $taxonomy,
				'term_id'  => $term_id,
				'name'     => $term->name,
			);
		}

		$result = wp_delete_term( $term_id, $taxonomy );
		if ( is_wp_error( $result ) ) {
			throw new \Exception( esc_html( $result->get_error_message() ) );
		}

		return array(
			'success'  => true,
			'term_id'  => $term_id,
			'taxonomy' => $taxonomy,
			'message'  => "Term ID {$term_id} deleted.",
		);
	}
}
