<?php
/**
 * CPT Builder PHP code export.
 *
 * @package CptBuilder
 * @since 1.2.0
 */

namespace CptBuilder;

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

/**
 * Generates register_post_type() / register_taxonomy() PHP snippets.
 */
final class PhpExport {

	private Storage $storage;

	private Registrar $registrar;

	private ?TaxonomyStorage $taxonomy_storage;

	private ?TaxonomyRegistrar $taxonomy_registrar;

	public function __construct(
		Storage $storage,
		Registrar $registrar,
		?TaxonomyStorage $taxonomy_storage = null,
		?TaxonomyRegistrar $taxonomy_registrar = null
	) {
		$this->storage            = $storage;
		$this->registrar          = $registrar;
		$this->taxonomy_storage   = $taxonomy_storage;
		$this->taxonomy_registrar = $taxonomy_registrar;
	}

	/**
	 * Export one or all CPTs as PHP source.
	 *
	 * @param string|null $key Specific key or null for all.
	 */
	public function exportPhp( ?string $key = null ): string {
		$definitions = $this->storage->all();
		if ( $key !== null ) {
			$definitions = isset( $definitions[ $key ] ) ? [ $key => $definitions[ $key ] ] : [];
		}

		$blocks = [
			'<?php',
			'/**',
			' * Custom post types exported from WP PowerSuite CPT Builder.',
			' * Generated: ' . gmdate( 'Y-m-d H:i:s' ) . ' UTC',
			' *',
			' * Paste into a theme functions.php or a custom plugin.',
			' */',
			'',
			"add_action( 'init', function () {",
		];

		$rendered = 0;
		foreach ( $definitions as $pt_key => $definition ) {
			if ( ! is_array( $definition ) ) {
				continue;
			}

			// Single-key export always includes the definition; bulk export skips disabled.
			if ( $key === null && empty( $definition['enabled'] ) ) {
				continue;
			}

			$blocks[] = $this->renderPostType( (string) $pt_key, $definition );
			$blocks[] = '';
			++$rendered;
		}

		if ( $rendered === 0 ) {
			$blocks[] = "\t// No post types to export.";
			$blocks[] = '';
		}

		$blocks[] = '}, 9 );';
		$blocks[] = '';

		return implode( "\n", $blocks );
	}

	/**
	 * Export one or all taxonomies as PHP source.
	 *
	 * @param string|null $key Specific key or null for all.
	 */
	public function exportTaxonomyPhp( ?string $key = null ): string {
		$tax_storage   = $this->taxonomy_storage ?? new TaxonomyStorage();
		$tax_registrar = $this->taxonomy_registrar ?? new TaxonomyRegistrar( $tax_storage );

		$definitions = $tax_storage->all();
		if ( $key !== null ) {
			$definitions = isset( $definitions[ $key ] ) ? [ $key => $definitions[ $key ] ] : [];
		}

		$blocks = [
			'<?php',
			'/**',
			' * Custom taxonomies exported from WP PowerSuite CPT Builder.',
			' * Generated: ' . gmdate( 'Y-m-d H:i:s' ) . ' UTC',
			' *',
			' * Paste into a theme functions.php or a custom plugin.',
			' */',
			'',
			"add_action( 'init', function () {",
		];

		$rendered = 0;
		foreach ( $definitions as $tax_key => $definition ) {
			if ( ! is_array( $definition ) ) {
				continue;
			}

			if ( $key === null && empty( $definition['enabled'] ) ) {
				continue;
			}

			$blocks[] = $this->renderTaxonomy( (string) $tax_key, $definition, $tax_registrar );
			$blocks[] = '';
			++$rendered;
		}

		if ( $rendered === 0 ) {
			$blocks[] = "\t// No taxonomies to export.";
			$blocks[] = '';
		}

		$blocks[] = '}, 8 );';
		$blocks[] = '';

		return implode( "\n", $blocks );
	}

	/**
	 * @param string               $key        Post type key.
	 * @param array<string, mixed> $definition Stored definition.
	 */
	private function renderPostType( string $key, array $definition ): string {
		$args       = $this->registrar->buildArgs( $key, $definition );
		$taxonomies = isset( $definition['taxonomies'] ) && is_array( $definition['taxonomies'] )
			? array_values( array_filter( array_map( 'strval', $definition['taxonomies'] ) ) )
			: [];
		$label      = (string) ( $definition['labels']['singular_name'] ?? $key );

		$lines   = [];
		if ( empty( $definition['enabled'] ) ) {
			$lines[] = "\t// Disabled in CPT Builder — exported for reference.";
		}
		$lines[] = "\t// " . $label;
		$lines[] = "\tregister_post_type( '" . $key . "', " . $this->exportVar( $args, 1 ) . ' );';

		foreach ( $taxonomies as $taxonomy ) {
			$lines[] = "\tif ( taxonomy_exists( '" . $taxonomy . "' ) ) {";
			$lines[] = "\t\tregister_taxonomy_for_object_type( '" . $taxonomy . "', '" . $key . "' );";
			$lines[] = "\t}";
		}

		return implode( "\n", $lines );
	}

	/**
	 * @param string               $key        Taxonomy key.
	 * @param array<string, mixed> $definition Stored definition.
	 */
	private function renderTaxonomy( string $key, array $definition, TaxonomyRegistrar $registrar ): string {
		$args         = $registrar->buildArgs( $key, $definition );
		$object_types = isset( $definition['object_types'] ) && is_array( $definition['object_types'] )
			? array_values( array_filter( array_map( 'strval', $definition['object_types'] ) ) )
			: [];
		$label        = (string) ( $definition['labels']['singular_name'] ?? $key );

		$lines = [];
		if ( empty( $definition['enabled'] ) ) {
			$lines[] = "\t// Disabled in CPT Builder — exported for reference.";
		}
		$lines[] = "\t// " . $label;
		$lines[] = "\tregister_taxonomy( '" . $key . "', " . $this->exportVar( $object_types, 1 ) . ', ' . $this->exportVar( $args, 1 ) . ' );';

		return implode( "\n", $lines );
	}

	/**
	 * @param mixed $value  PHP value.
	 * @param int   $indent Indent depth.
	 */
	private function exportVar( mixed $value, int $indent = 0 ): string {
		$pad = str_repeat( "\t", $indent );

		if ( is_array( $value ) ) {
			if ( $value === [] ) {
				return '[]';
			}
			$is_list = array_is_list( $value );
			$parts   = [];
			foreach ( $value as $k => $v ) {
				$key_part = $is_list ? '' : $this->exportVar( $k, 0 ) . ' => ';
				$parts[]  = $pad . "\t" . $key_part . $this->exportVar( $v, $indent + 1 );
			}

			return "[\n" . implode( ",\n", $parts ) . ",\n" . $pad . ']';
		}

		if ( is_bool( $value ) ) {
			return $value ? 'true' : 'false';
		}

		if ( is_int( $value ) || is_float( $value ) ) {
			return (string) $value;
		}

		if ( $value === null ) {
			return 'null';
		}

		return var_export( (string) $value, true );
	}
}
