<?php
/**
 * Catálogo de tamaños para códigos de etiqueta.
 *
 * @package Logistica
 */

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

/**
 * Opciones de tamaño persistidas (wp_options) + usadas en registros.
 */
class Logistica_Label_Etiqueta_Tamanos {

	const OPTION_KEY        = 'logistica_etiqueta_tamanos';
	const HIDDEN_OPTION_KEY = 'logistica_etiqueta_tamanos_ocultos';

	/**
	 * @return array<string, array{label:string}>
	 */
	public static function get_hidden() {
		$hidden = get_option( self::HIDDEN_OPTION_KEY, array() );

		if ( ! is_array( $hidden ) ) {
			return array();
		}

		$clean = array();
		foreach ( $hidden as $key => $entry ) {
			$key = strtolower( self::normalize_label( $key ) );
			if ( '' === $key ) {
				continue;
			}

			if ( true === $entry || 1 === $entry || '1' === $entry ) {
				$clean[ $key ] = array( 'label' => self::normalize_label( $key ) );
				continue;
			}

			if ( ! is_array( $entry ) ) {
				continue;
			}

			$label = trim( sanitize_text_field( (string) ( $entry['label'] ?? '' ) ) );
			if ( '' === $label ) {
				$label = self::normalize_label( $key );
			}

			$clean[ $key ] = array(
				'label' => $label,
			);
		}

		return $clean;
	}

	/**
	 * @param mixed $label Texto del tamaño.
	 * @return bool
	 */
	public static function is_hidden( $label ) {
		$label = strtolower( self::normalize_label( $label ) );

		return '' !== $label && isset( self::get_hidden()[ $label ] );
	}

	/**
	 * @param mixed  $label Texto del tamaño.
	 * @param string $snapshot Etiqueta visible al ocultar.
	 * @return void
	 */
	private static function hide_label( $label, $snapshot = '' ) {
		$key = strtolower( self::normalize_label( $label ) );
		if ( '' === $key ) {
			return;
		}

		$snapshot = '' !== trim( (string) $snapshot ) ? self::normalize_label( $snapshot ) : self::normalize_label( $label );

		$hidden         = self::get_hidden();
		$hidden[ $key ] = array(
			'label' => $snapshot,
		);
		update_option( self::HIDDEN_OPTION_KEY, $hidden, false );
	}

	/**
	 * @param mixed $label Texto del tamaño.
	 * @return void
	 */
	private static function unhide_label( $label ) {
		$key = strtolower( self::normalize_label( $label ) );
		if ( '' === $key ) {
			return;
		}

		$hidden = self::get_hidden();
		if ( ! isset( $hidden[ $key ] ) ) {
			return;
		}

		unset( $hidden[ $key ] );
		update_option( self::HIDDEN_OPTION_KEY, $hidden, false );
	}

	/**
	 * @return list<string>
	 */
	public static function get_saved() {
		$saved = get_option( self::OPTION_KEY, array() );

		if ( ! is_array( $saved ) ) {
			return array();
		}

		$clean = array();
		foreach ( $saved as $item ) {
			$label = self::normalize_label( $item );
			if ( '' !== $label ) {
				$clean[] = $label;
			}
		}

		return array_values( array_unique( $clean ) );
	}

	/**
	 * Lista ordenada: guardados + distintos en la tabla de productos.
	 *
	 * @return list<string>
	 */
	public static function get_options() {
		global $wpdb;

		$merged = array();
		$push   = static function ( $label ) use ( &$merged ) {
			$label = self::normalize_label( $label );
			if ( '' === $label || self::is_hidden( $label ) ) {
				return;
			}
			$key = strtolower( $label );
			if ( ! isset( $merged[ $key ] ) ) {
				$merged[ $key ] = $label;
			}
		};

		foreach ( self::get_saved() as $label ) {
			$push( $label );
		}

		$table = Logistica_Database::table( 'etiqueta_productos' );
		if ( $table ) {
			$rows = $wpdb->get_col( "SELECT DISTINCT tamano FROM {$table} WHERE tamano <> '' ORDER BY tamano ASC" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
			if ( is_array( $rows ) ) {
				foreach ( $rows as $row ) {
					$push( $row );
				}
			}
		}

		$values = array_values( $merged );
		natcasesort( $values );

		return array_values( $values );
	}

	/**
	 * @param mixed $label Texto del tamaño.
	 * @return string
	 */
	public static function normalize_label( $label ) {
		$label = trim( sanitize_text_field( (string) $label ) );

		return function_exists( 'mb_strtoupper' )
			? mb_strtoupper( $label, 'UTF-8' )
			: strtoupper( $label );
	}

	/**
	 * @return list<array{label:string,can_delete:bool}>
	 */
	public static function get_admin_entries() {
		$entries = array();
		foreach ( self::get_options() as $label ) {
			$entries[] = array(
				'label'      => (string) $label,
				'can_delete' => true,
			);
		}

		return $entries;
	}

	/**
	 * @param string $old_label Valor actual.
	 * @param mixed  $new_label Nuevo texto.
	 * @return string|\WP_Error
	 */
	public static function update( $old_label, $new_label ) {
		global $wpdb;

		$old_label = self::normalize_label( $old_label );
		$new_label = self::normalize_label( $new_label );

		if ( '' === $old_label || '' === $new_label ) {
			return new WP_Error( 'invalid_tamano', __( 'Indica el tamaño.', 'logistica' ) );
		}

		if ( 0 === strcasecmp( $old_label, $new_label ) ) {
			return $old_label;
		}

		foreach ( self::get_options() as $existing ) {
			if ( 0 === strcasecmp( $existing, $new_label ) && 0 !== strcasecmp( $existing, $old_label ) ) {
				return new WP_Error( 'duplicate_tamano', __( 'Ese tamaño ya existe.', 'logistica' ) );
			}
		}

		$saved = self::get_saved();
		$found = false;
		foreach ( $saved as $index => $item ) {
			if ( 0 === strcasecmp( $item, $old_label ) ) {
				$saved[ $index ] = $new_label;
				$found           = true;
				break;
			}
		}
		if ( ! $found ) {
			$saved[] = $new_label;
		}
		update_option( self::OPTION_KEY, array_values( array_unique( $saved ) ), false );

		$table = Logistica_Database::table( 'etiqueta_productos' );
		if ( $table ) {
			$wpdb->query(
				$wpdb->prepare(
					"UPDATE {$table} SET tamano = %s WHERE tamano = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
					$new_label,
					$old_label
				)
			);
		}

		return $new_label;
	}

	/**
	 * @param mixed $label Texto del tamaño.
	 * @return true|\WP_Error
	 */
	public static function remove( $label ) {
		$label = self::normalize_label( $label );
		if ( '' === $label ) {
			return new WP_Error( 'invalid_tamano', __( 'Indica el tamaño.', 'logistica' ) );
		}

		if ( self::is_hidden( $label ) ) {
			return new WP_Error( 'already_hidden', __( 'El tamaño ya está oculto.', 'logistica' ) );
		}

		$saved   = self::get_saved();
		$updated = array();

		foreach ( $saved as $item ) {
			if ( 0 === strcasecmp( $item, $label ) ) {
				continue;
			}
			$updated[] = $item;
		}

		update_option( self::OPTION_KEY, array_values( array_unique( $updated ) ), false );
		self::hide_label( $label, $label );

		Logistica_Label_Option_Lifecycle::record_remove(
			'tamano',
			$label,
			$label,
			array(
				'key'    => $label,
				'label'  => $label,
				'hidden' => array( 'label' => $label ),
				'saved'  => in_array( $label, $saved, true ) ? $label : null,
			)
		);

		return true;
	}

	/**
	 * @param array<string, mixed> $payload Snapshot papelera.
	 * @return true|\WP_Error
	 */
	public static function apply_restore_from_payload( $payload ) {
		$label = self::normalize_label( (string) ( $payload['key'] ?? $payload['label'] ?? '' ) );
		if ( '' === $label ) {
			return new WP_Error( 'invalid_tamano', __( 'No hay tamaño para restaurar.', 'logistica' ) );
		}

		if ( ! empty( $payload['saved'] ) ) {
			$saved = self::get_saved();
			if ( ! in_array( $label, $saved, true ) ) {
				$saved[] = $label;
				update_option( self::OPTION_KEY, array_values( array_unique( $saved ) ), false );
			}
		}

		self::unhide_label( $label );

		return true;
	}

	/**
	 * @param mixed $label Texto del tamaño oculto.
	 * @return true|\WP_Error
	 */
	public static function restore( $label ) {
		$label = self::normalize_label( $label );
		if ( '' === $label || ! self::is_hidden( $label ) ) {
			return new WP_Error( 'not_hidden', __( 'El tamaño no está en la lista de ocultos.', 'logistica' ) );
		}

		self::unhide_label( $label );

		Logistica_Label_Option_Lifecycle::record_restore( 'tamano', $label, $label );

		return true;
	}

	/**
	 * @return list<array{kind:string,key:string,label:string,meta:string,usage:int}>
	 */
	public static function get_hidden_admin_entries() {
		$entries = array();
		$hidden  = self::get_hidden();

		foreach ( $hidden as $key => $meta ) {
			$label = trim( (string) ( $meta['label'] ?? '' ) );
			if ( '' === $label ) {
				$label = self::normalize_label( $key );
			}

			$entries[] = array(
				'kind'  => 'tamano',
				'key'   => $label,
				'label' => $label,
				'meta'  => '',
				'usage' => Logistica_Label_Etiqueta_Option_Usage::count_tamano( $label ),
			);
		}

		usort(
			$entries,
			static function ( $a, $b ) {
				return strnatcasecmp( (string) $a['label'], (string) $b['label'] );
			}
		);

		return $entries;
	}

	/**
	 * Registra un tamaño nuevo en la lista guardada.
	 *
	 * @param mixed $label Texto del tamaño.
	 * @return string|\WP_Error Etiqueta canónica guardada.
	 */
	public static function add( $label ) {
		$label = self::normalize_label( $label );
		if ( '' === $label ) {
			return new WP_Error( 'empty_tamano', __( 'Indica el tamaño.', 'logistica' ) );
		}

		foreach ( self::get_options() as $existing ) {
			if ( 0 === strcasecmp( $existing, $label ) ) {
				return $existing;
			}
		}

		self::unhide_label( $label );

		$saved   = self::get_saved();
		$saved[] = $label;
		update_option( self::OPTION_KEY, array_values( array_unique( $saved ) ), false );

		return $label;
	}

	/**
	 * @param mixed $label Texto del tamaño.
	 * @return string
	 */
	public static function remember( $label ) {
		$result = self::add( $label );

		return is_wp_error( $result ) ? self::normalize_label( $label ) : (string) $result;
	}
}
