<?php
/**
 * API unificada de trazabilidad para módulos del plugin.
 *
 * Uso opt-in: los módulos existentes siguen funcionando sin cambios hasta que
 * llamen explícitamente a estos métodos en sus flujos de guardado/eliminación.
 *
 * @package Logistica
 */

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

/**
 * Fachada modular para auditoría, papelera e historial de versiones.
 */
class Logistica_Entity_Lifecycle {

	/**
	 * @return void
	 */
	public static function init() {
		Logistica_Module_Registry::register_defaults();
	}

	/**
	 * @param string               $module_key  Módulo registrado.
	 * @param string               $entity_type Tipo de entidad.
	 * @param string               $entity_id   ID estable.
	 * @param array<string, mixed> $payload     Estado guardado.
	 * @param string               $summary     Resumen legible.
	 * @return void
	 */
	public static function record_create( $module_key, $entity_type, $entity_id, $payload, $summary = '' ) {
		if ( ! Logistica_Module_Registry::supports( $module_key, 'audit' ) ) {
			return;
		}

		Logistica_Audit::log(
			array(
				'module_key'     => $module_key,
				'entity_type'    => $entity_type,
				'entity_id'      => (string) $entity_id,
				'action'         => 'create',
				'summary'        => $summary ?: __( 'Registro creado', 'logistica' ),
				'payload_after'  => $payload,
			)
		);
	}

	/**
	 * @param string               $module_key     Módulo.
	 * @param string               $entity_type    Tipo.
	 * @param string               $entity_id      ID.
	 * @param array<string, mixed> $payload_before Estado anterior.
	 * @param array<string, mixed> $payload_after  Estado nuevo.
	 * @param string               $summary        Resumen.
	 * @param bool                 $save_version   Si guardar snapshot en historial.
	 * @return void
	 */
	public static function record_update( $module_key, $entity_type, $entity_id, $payload_before, $payload_after, $summary = '', $save_version = true ) {
		if ( $save_version && Logistica_Module_Registry::supports( $module_key, 'versions' ) && ! empty( $payload_before ) ) {
			Logistica_Version_History::save(
				array(
					'module_key'  => $module_key,
					'entity_type' => $entity_type,
					'entity_id'   => (string) $entity_id,
					'summary'     => $summary ?: __( 'Versión anterior', 'logistica' ),
					'payload'     => $payload_before,
				)
			);
		}

		if ( ! Logistica_Module_Registry::supports( $module_key, 'audit' ) ) {
			return;
		}

		Logistica_Audit::log(
			array(
				'module_key'     => $module_key,
				'entity_type'    => $entity_type,
				'entity_id'      => (string) $entity_id,
				'action'         => 'update',
				'summary'        => $summary ?: __( 'Registro actualizado', 'logistica' ),
				'payload_before' => $payload_before,
				'payload_after'  => $payload_after,
			)
		);
	}

	/**
	 * @param string               $module_key   Módulo.
	 * @param string               $entity_type  Tipo.
	 * @param string               $entity_id    ID.
	 * @param array<string, mixed> $payload      Snapshot al eliminar.
	 * @param string               $entity_label Etiqueta visible.
	 * @param string               $summary      Resumen.
	 * @return int ID en papelera.
	 */
	public static function record_delete( $module_key, $entity_type, $entity_id, $payload, $entity_label = '', $summary = '' ) {
		$trash_id = 0;

		if ( Logistica_Module_Registry::supports( $module_key, 'trash' ) ) {
			$trash_id = Logistica_Trash::add(
				array(
					'module_key'   => $module_key,
					'entity_type'  => $entity_type,
					'entity_id'    => (string) $entity_id,
					'entity_label' => $entity_label ?: (string) $entity_id,
					'payload'      => $payload,
				)
			);
		}

		if ( Logistica_Module_Registry::supports( $module_key, 'audit' ) ) {
			Logistica_Audit::log(
				array(
					'module_key'     => $module_key,
					'entity_type'    => $entity_type,
					'entity_id'      => (string) $entity_id,
					'action'         => 'delete',
					'summary'        => $summary ?: __( 'Registro enviado a papelera', 'logistica' ),
					'payload_before' => $payload,
					'meta'           => array(
						'trash_id' => $trash_id,
					),
				)
			);
		}

		return $trash_id;
	}

	/**
	 * @param int $trash_id ID en papelera.
	 * @return array<string, mixed>|WP_Error
	 */
	public static function restore_from_trash( $trash_id ) {
		if ( ! self::can_restore() ) {
			return new WP_Error( 'forbidden', __( 'No tienes permiso para restaurar registros.', 'logistica' ) );
		}

		$result = Logistica_Trash::restore( $trash_id );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		Logistica_Audit::log(
			array(
				'module_key'  => (string) ( $result['module_key'] ?? '' ),
				'entity_type' => (string) ( $result['entity_type'] ?? '' ),
				'entity_id'   => (string) ( $result['entity_id'] ?? '' ),
				'action'      => 'restore',
				'summary'     => __( 'Restaurado desde papelera', 'logistica' ),
				'meta'        => array(
					'trash_id' => (int) $trash_id,
				),
			)
		);

		return $result;
	}

	/**
	 * @param int $version_id ID de versión.
	 * @return array<string, mixed>|WP_Error
	 */
	public static function restore_version( $version_id ) {
		if ( ! self::can_restore() ) {
			return new WP_Error( 'forbidden', __( 'No tienes permiso para restaurar versiones.', 'logistica' ) );
		}

		return Logistica_Version_History::restore( $version_id );
	}

	/**
	 * Operador: crear y editar (acceso al plugin).
	 *
	 * @param int|null $user_id Usuario.
	 * @return bool
	 */
	public static function can_create_edit( $user_id = null ) {
		return Logistica_Roles::user_can_access_plugin( $user_id );
	}

	/**
	 * Supervisor: eliminación lógica.
	 *
	 * @param int|null $user_id Usuario.
	 * @return bool
	 */
	public static function can_soft_delete( $user_id = null ) {
		return Logistica_Roles::user_can_lifecycle_soft_delete( $user_id );
	}

	/**
	 * Administrador: restaurar desde papelera o historial.
	 *
	 * @param int|null $user_id Usuario.
	 * @return bool
	 */
	public static function can_restore( $user_id = null ) {
		return Logistica_Roles::user_can_lifecycle_restore( $user_id );
	}

	/**
	 * Administrador: eliminación definitiva.
	 *
	 * @param int|null $user_id Usuario.
	 * @return bool
	 */
	public static function can_purge( $user_id = null ) {
		return Logistica_Roles::user_can_lifecycle_purge( $user_id );
	}

	/**
	 * @param string               $module_key  Módulo.
	 * @param string               $entity_type Tipo.
	 * @param string               $entity_id   ID.
	 * @param array<string, mixed> $payload     Snapshot.
	 * @return void
	 */
	public static function record_purge( $module_key, $entity_type, $entity_id, $payload ) {
		if ( Logistica_Module_Registry::supports( $module_key, 'audit' ) ) {
			Logistica_Audit::log(
				array(
					'module_key'     => $module_key,
					'entity_type'    => $entity_type,
					'entity_id'      => (string) $entity_id,
					'action'         => 'purge',
					'summary'        => __( 'Eliminación definitiva', 'logistica' ),
					'payload_before' => $payload,
				)
			);
		}
	}

	/**
	 * @return string
	 */
	public static function client_ip() {
		$candidates = array(
			'HTTP_CLIENT_IP',
			'HTTP_X_FORWARDED_FOR',
			'HTTP_X_REAL_IP',
			'REMOTE_ADDR',
		);

		foreach ( $candidates as $key ) {
			if ( empty( $_SERVER[ $key ] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
				continue;
			}

			$raw = sanitize_text_field( wp_unslash( (string) $_SERVER[ $key ] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			if ( str_contains( $raw, ',' ) ) {
				$raw = trim( explode( ',', $raw )[0] );
			}

			if ( filter_var( $raw, FILTER_VALIDATE_IP ) ) {
				return $raw;
			}
		}

		return '';
	}

	/**
	 * @param string $scope audit|trash|versions.
	 * @param array<string, mixed> $args Filtros.
	 * @return array{items: array<int, array<string, mixed>>, total: int}
	 */
	public static function query( $scope, $args = array() ) {
		switch ( $scope ) {
			case 'trash':
				return Logistica_Trash::query( $args );
			case 'versions':
				return Logistica_Version_History::query( $args );
			case 'audit':
			default:
				return Logistica_Audit::query( $args );
		}
	}

	/**
	 * Exporta filas visibles según filtros a CSV.
	 *
	 * @param string               $scope audit|trash|versions.
	 * @param array<string, mixed> $args  Filtros (sin paginación).
	 * @return void
	 */
	public static function export_csv( $scope, $args = array() ) {
		$args['page']      = 1;
		$args['page_size'] = 10000;
		$result            = self::query( $scope, $args );
		$items             = $result['items'] ?? array();

		$filename = 'logistica-' . sanitize_file_name( $scope ) . '-' . gmdate( 'Y-m-d' ) . '.csv';
		nocache_headers();
		header( 'Content-Type: text/csv; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename="' . $filename . '"' );

		$out = fopen( 'php://output', 'w' );
		if ( ! $out ) {
			exit;
		}

		fprintf( $out, chr( 0xEF ) . chr( 0xBB ) . chr( 0xBF ) );

		if ( 'trash' === $scope ) {
			fputcsv( $out, array( 'ID', 'Módulo', 'Tipo', 'Etiqueta', 'ID entidad', 'Estado', 'Eliminado por', 'Eliminado', 'Restaurado por', 'Restaurado' ) );
			foreach ( $items as $item ) {
				fputcsv(
					$out,
					array(
						$item['id'] ?? '',
						$item['module_label'] ?? '',
						$item['entity_type'] ?? '',
						$item['entity_label'] ?? '',
						$item['entity_id'] ?? '',
						$item['status'] ?? '',
						$item['deleted_by_name'] ?? '',
						$item['deleted_at'] ?? '',
						$item['restored_by_name'] ?? '',
						$item['restored_at'] ?? '',
					)
				);
			}
		} elseif ( 'versions' === $scope ) {
			fputcsv( $out, array( 'ID', 'Módulo', 'Tipo', 'ID entidad', 'Versión', 'Resumen', 'Usuario', 'Fecha' ) );
			foreach ( $items as $item ) {
				fputcsv(
					$out,
					array(
						$item['id'] ?? '',
						$item['module_label'] ?? '',
						$item['entity_type'] ?? '',
						$item['entity_id'] ?? '',
						$item['version_no'] ?? '',
						$item['summary'] ?? '',
						$item['created_by_name'] ?? '',
						$item['created_at'] ?? '',
					)
				);
			}
		} else {
			fputcsv( $out, array( 'ID', 'Módulo', 'Tipo', 'ID entidad', 'Acción', 'Resumen', 'Usuario', 'Fecha', 'IP' ) );
			foreach ( $items as $item ) {
				fputcsv(
					$out,
					array(
						$item['id'] ?? '',
						$item['module_label'] ?? '',
						$item['entity_type'] ?? '',
						$item['entity_id'] ?? '',
						$item['action'] ?? '',
						$item['summary'] ?? '',
						$item['created_by_name'] ?? '',
						$item['created_at'] ?? '',
						$item['ip_address'] ?? '',
					)
				);
			}
		}

		fclose( $out );
		exit;
	}
}
