<?php
/**
 * Taxonomy Management
 *
 * This file contains all taxonomy-related functionality for automated post categorization.
 *
 * @package Simple_Ai_Auto_Post
 * @since 1.1.4
 */

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

// Make sure this file is being included by a parent file.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Apply categories and tags to a WordPress post
 *
 * @param int $post_id The post ID to apply taxonomy to
 * @param array $taxonomy_suggestions A structured array of taxonomy suggestions, e.g., ['category' => ['News'], 'post_tag' => ['featured']]
 * @return bool|WP_Error True on success, WP_Error on failure
 */
function saiap_apply_post_taxonomy( $post_id, $taxonomy_suggestions = array() ) {
	
	if ( ! $post_id || ! is_numeric( $post_id ) ) {
		return new WP_Error( 'invalid_post_id', 'Invalid post ID provided' );
	}

	$post = get_post( $post_id );
	if ( ! $post ) {
		return new WP_Error( 'post_not_found', 'Post not found' );
	}

	$errors = array();
	$all_term_ids = array();

	// When false (default), the AI taxonomy flow can only assign existing terms;
	// it never creates new ones. Prevents the singleton-tag sprawl that produces
	// thin archive pages.
	$allow_create = (bool) get_option( 'saiap_allow_ai_create_terms', false );

	if ( ! empty( $taxonomy_suggestions ) && is_array( $taxonomy_suggestions ) ) {
		foreach ( $taxonomy_suggestions as $tax_slug => $terms ) {
            
			
            if ( empty( $terms ) ) {
                continue;
            }
			$taxonomy_obj = get_taxonomy( $tax_slug );
            if ( ! $taxonomy_obj ) {
                continue;
            }
			
            
			
			$term_ids = array();
			
			// Handle raw terms from AI
            if ( is_array( $terms ) && isset( $terms[0] ) && is_array( $terms[0] ) && isset( $terms[0]['name'] ) ) {
				
				// First pass: Create all terms and build a map of suggested term_id to actual term_id
				$term_id_map = array();
				foreach ( $terms as $term_data ) {
					$term_name = trim( $term_data['name'] );
					$term_slug = isset( $term_data['slug'] ) ? trim( $term_data['slug'] ) : sanitize_title( $term_name );
					$term_description = isset( $term_data['description'] ) ? trim( $term_data['description'] ) : '';
					$suggested_parent = isset( $term_data['parent'] ) ? intval( $term_data['parent'] ) : 0;
					
					if ( empty( $term_name ) ) {
						continue;
					}

                    
					
					// Check if term exists by name (exact match).
					$existing_term = get_term_by( 'name', $term_name, $tax_slug );
					// Backstop: try slug match in case the model paraphrased
					// case/punctuation ("Family Law" → "family-law" slug).
					if ( ! $existing_term && ! empty( $term_slug ) ) {
						$existing_term = get_term_by( 'slug', $term_slug, $tax_slug );
					}
					if ( ! $existing_term ) {
						$existing_term = get_term_by( 'slug', sanitize_title( $term_name ), $tax_slug );
					}
					if ( ! $existing_term ) {
						if ( ! $allow_create ) {
							// Setting off (default): silently skip rather than create
							// a singleton tag/category. Customer controls vocabulary.
							continue;
						}
						// Create new term
						$term_args = array();
						if ( $taxonomy_obj->hierarchical && $suggested_parent > 0 ) {
							// For hierarchical taxonomies, we need to find the actual parent term_id
							$actual_parent_id = isset( $term_id_map[ $suggested_parent ] ) ? $term_id_map[ $suggested_parent ] : 0;
                            if ( $actual_parent_id > 0 ) {
                                $term_args['parent'] = $actual_parent_id;
                            }
						}

						$term_result = wp_insert_term( $term_name, $tax_slug, $term_args );
                        if ( ! is_wp_error( $term_result ) ) {
							$actual_term_id = $term_result['term_id'];
							$term_ids[] = $actual_term_id;
							// Map the suggested term_id to the actual term_id for parent relationships
							$suggested_term_id = isset( $term_data['term_id'] ) ? intval( $term_data['term_id'] ) : count( $term_id_map ) + 1;
							$term_id_map[ $suggested_term_id ] = $actual_term_id;
						} else {
							$errors[] = $term_result->get_error_message();
						}
					} else {
						// Term already exists
						$actual_term_id = $existing_term->term_id;
						$term_ids[] = $actual_term_id;
                        // Map the suggested term_id to the actual term_id
						$suggested_term_id = isset( $term_data['term_id'] ) ? intval( $term_data['term_id'] ) : count( $term_id_map ) + 1;
						$term_id_map[ $suggested_term_id ] = $actual_term_id;
                        
					}
				}
				
				// Second pass: Update parent relationships for hierarchical taxonomies
				if ( $taxonomy_obj->hierarchical ) {
					foreach ( $terms as $term_data ) {
						$term_name = trim( $term_data['name'] );
						$suggested_parent = isset( $term_data['parent'] ) ? intval( $term_data['parent'] ) : 0;
						
						if ( $suggested_parent > 0 ) {
							$suggested_term_id = isset( $term_data['term_id'] ) ? intval( $term_data['term_id'] ) : 0;
							$actual_term_id = isset( $term_id_map[ $suggested_term_id ] ) ? $term_id_map[ $suggested_term_id ] : 0;
							$actual_parent_id = isset( $term_id_map[ $suggested_parent ] ) ? $term_id_map[ $suggested_parent ] : 0;
							
							if ( $actual_term_id > 0 && $actual_parent_id > 0 ) {
                                $update_result = wp_update_term( $actual_term_id, $tax_slug, array( 'parent' => $actual_parent_id ) );
                                if ( is_wp_error( $update_result ) ) {
                                    // collect error silently
                                }
							}
						}
					}
				}
			} 
			
            if ( ! empty( $term_ids ) ) {
                $all_term_ids[ $tax_slug ] = $term_ids;
            }
		}
	}

    

	$success_count = 0;
	foreach ( $all_term_ids as $tax_slug => $term_ids_to_apply ) {
		$result = wp_set_post_terms( $post_id, $term_ids_to_apply, $tax_slug, true ); // Append terms
        if ( ! is_wp_error( $result ) ) {
			$success_count += count( $term_ids_to_apply );
			if ( $tax_slug === 'category' && ! empty( $term_ids_to_apply ) ) {
				wp_remove_object_terms( $post_id, 1, 'category' );
			}
		} else {
			$errors[] = $result->get_error_message();
		}
	}

    

	if ( ! empty( $errors ) ) {
		return new WP_Error( 'taxonomy_application_error', implode( '; ', $errors ) );
	}

	if ( $success_count === 0 ) {
		return new WP_Error( 'no_taxonomy_applied', 'No categories or tags were applied' );
	}

	return true;
}

/**
 * Recursive helper function to create nested terms.
 *
 * @param array $terms The array of terms to create (can be nested).
 * @param string $tax_slug The taxonomy slug.
 * @param int $parent_id The ID of the parent term.
 * @param array &$term_ids An array to collect the term IDs.
 * @param array &$errors An array to collect any errors.
 */
function saiap_create_nested_terms( $terms, $tax_slug, $parent_id, &$term_ids, &$errors ) {
	
	foreach ( $terms as $key => $value ) {
		$term_name = is_string( $key ) ? $key : $value;
		$children = is_string( $key ) ? $value : array();

        

		if ( is_array( $term_name ) ) {
			// Handle cases where the array is not associative
            
			foreach ( $term_name as $sub_key => $sub_value ) {
				saiap_create_nested_terms( array( $sub_key => $sub_value ), $tax_slug, $parent_id, $term_ids, $errors );
			}
			continue;
		}

		$term_name = trim( $term_name );
        if ( empty( $term_name ) ) {
            continue;
        }

		$term = get_term_by( 'name', $term_name, $tax_slug );
		if ( ! $term ) {
			$term_result = wp_insert_term( $term_name, $tax_slug, array( 'parent' => $parent_id ) );
			if ( ! is_wp_error( $term_result ) ) {
				$current_term_id = $term_result['term_id'];
			} else {
				$errors[] = "Failed to create term '{$term_name}': " . $term_result->get_error_message();
				continue;
			}
		} else {
			$current_term_id = $term['term_id'];
		}

		$term_ids[] = $current_term_id;

        if ( ! empty( $children ) && is_array( $children ) ) {
			saiap_create_nested_terms( $children, $tax_slug, $current_term_id, $term_ids, $errors );
		} else {
            
		}
	}
    
}

/**
 * Orchestrate post taxonomy editing using AI analysis
 *
 * @param int $post_id The post ID to edit taxonomy for
 * @return bool|WP_Error True on success, WP_Error on failure
 */
function saiap_edit_post_taxonomy( $post_id ) {
	if ( ! $post_id || ! is_numeric( $post_id ) ) {
		return new WP_Error( 'invalid_post_id', 'Invalid post ID provided' );
	}

	$post = get_post( $post_id );
	if ( ! $post ) {
		return new WP_Error( 'post_not_found', 'Post not found' );
	}

	$post_content = $post->post_content;
	if ( empty( $post_content ) ) {
		return new WP_Error( 'empty_post_content', 'Post content is empty' );
	}

	$license_key = get_option( 'saiap_license_key' );
	$domain = saiap_get_server_host();

	// Get all available taxonomies for the post type to send to the AI.
	// Also include the site's existing terms so the AI classifies into them
	// instead of inventing fresh variants ("Family Law" vs "family law").
	$post_type = get_post_type( $post );
	$all_taxonomies = get_object_taxonomies( $post_type, 'objects' );
	$available_taxonomies = array();
	foreach ( $all_taxonomies as $slug => $tax ) {
		$existing_terms = get_terms(
			array(
				'taxonomy'   => $slug,
				'hide_empty' => false,
				'number'     => 200,
				'orderby'    => 'count',
				'order'      => 'DESC',
			)
		);
		$term_list = array();
		if ( ! is_wp_error( $existing_terms ) ) {
			foreach ( $existing_terms as $t ) {
				$term_list[] = array(
					'name'  => $t->name,
					'slug'  => $t->slug,
					'count' => (int) $t->count,
				);
			}
		}
		$available_taxonomies[ $slug ] = array(
			'label'          => $tax->label,
			'hierarchical'   => $tax->hierarchical,
			'existing_terms' => $term_list,
		);
	}

	if ( empty( $available_taxonomies ) ) {
		return new WP_Error( 'no_taxonomies_found', 'No taxonomies are registered for this post type.' );
	}

    

	// Attempt to get taxonomy_settings from cached context or fetch fresh
	$taxonomy_settings = '';
	$cached_context    = get_transient( 'saiap_site_context_data' );
	if ( ! $cached_context ) {
		$cached_context = get_option( 'saiap_context_cache', null );
	}
	if ( is_array( $cached_context ) && isset( $cached_context['taxonomy_settings'] ) && ! empty( $cached_context['taxonomy_settings'] ) ) {
        $taxonomy_settings = $cached_context['taxonomy_settings'];
	}
    if ( empty( $taxonomy_settings ) ) {
		$context_response = wp_remote_post(
			'https://saiap.gopurposego.com/api/context',
			array(
				'headers' => array(
					'Content-Type' => 'application/json',
					'Accept'       => 'application/json',
				),
				'body'    => wp_json_encode(
					array(
						'license_key' => $license_key,
						'domain'      => $domain,
					)
				),
				'timeout' => 30,
			)
		);
		if ( ! is_wp_error( $context_response ) ) {
			$context_status = wp_remote_retrieve_response_code( $context_response );
			$context_body   = wp_remote_retrieve_body( $context_response );
			$context_data   = json_decode( $context_body, true );
			if ( 200 === $context_status && isset( $context_data['context']['taxonomy_settings'] ) && ! empty( $context_data['context']['taxonomy_settings'] ) ) {
                $taxonomy_settings = $context_data['context']['taxonomy_settings'];
			}
		}
	}

	$payload = array(
		'license_key'  => $license_key,
		'domain'       => $domain,
		'post_content' => $post_content,
	);
	if ( ! empty( $taxonomy_settings ) ) {
		$payload['taxonomy_settings'] = is_array( $taxonomy_settings ) ? wp_json_encode( $taxonomy_settings ) : (string) $taxonomy_settings;
    } else {
    }
	$payload['availableTaxonomies'] = $available_taxonomies;

	$api_response = wp_remote_post(
		'https://saiap.gopurposego.com/api/taxonomy/analyze',
		array(
			'headers' => array(
				'Content-Type' => 'application/json',
			),
			'body'    => wp_json_encode( $payload ),
			'timeout' => 60,
		)
	);

    

	if ( is_wp_error( $api_response ) ) {
		return new WP_Error( 'api_request_failed', 'Taxonomy analysis API request failed: ' . $api_response->get_error_message() );
	}

	$response_code = wp_remote_retrieve_response_code( $api_response );
	if ( $response_code !== 200 ) {
		$response_body = wp_remote_retrieve_body( $api_response );
		$error_data    = json_decode( $response_body, true );
		$error_message = isset( $error_data['error'] ) ? $error_data['error'] : 'Unknown API error';
		return new WP_Error( 'api_error', 'Taxonomy analysis failed: ' . $error_message );
	}

	$response_body = wp_remote_retrieve_body( $api_response );
	$taxonomy_data = json_decode( $response_body, true );

    

	$result_key = null;
	if ( isset( $taxonomy_data['taxonomies'] ) && ! empty( $taxonomy_data['taxonomies'] ) ) {
		$result_key = 'taxonomies';
	} elseif ( isset( $taxonomy_data['taxonomy'] ) && ! empty( $taxonomy_data['taxonomy'] ) ) {
		$result_key = 'taxonomy';
	}
    if ( ! $result_key ) {
		return new WP_Error( 'no_taxonomy_suggestions', 'No taxonomy suggestions received from AI' );
	}

    

	$apply_result = saiap_apply_post_taxonomy( $post_id, $taxonomy_data[ $result_key ] );
	
	if ( is_wp_error( $apply_result ) ) {
		return $apply_result;
	}

	return true;
}