<?php
/**
 * Data access for the `embp_suppliers` table.
 *
 * @package EmberPrice
 */

namespace EmberPrice\Core;

defined( 'ABSPATH' ) || exit;

/**
 * Lives in Core (not Ingestion) because suppliers are read/written across
 * the whole pipeline (Ingestion, Matching, Apply), and those layers can't
 * import each other per the dependency matrix in CLAUDE.md -- only Core.
 */
final class Suppliers {

	/**
	 * All suppliers, ordered by name.
	 */
	public function all(): array {
		global $wpdb;
		$table = $wpdb->prefix . 'embp_suppliers';

		$rows = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i ORDER BY name ASC', $table ), ARRAY_A );

		return array_map( array( $this, 'hydrate' ), null !== $rows ? $rows : array() );
	}

	/**
	 * Finds a supplier by id, or null if it doesn't exist.
	 *
	 * @param int $id Supplier id.
	 */
	public function find( int $id ): ?array {
		global $wpdb;
		$table = $wpdb->prefix . 'embp_suppliers';

		$row = $wpdb->get_row(
			$wpdb->prepare( 'SELECT * FROM %i WHERE id = %d', $table, $id ),
			ARRAY_A
		);

		return null === $row ? null : $this->hydrate( $row );
	}

	/**
	 * Creates a new supplier with empty rule/mapping/settings, returning its id.
	 *
	 * @param string $name Supplier name.
	 */
	public function create( string $name ): int {
		global $wpdb;
		$table = $wpdb->prefix . 'embp_suppliers';

		$wpdb->insert(
			$table,
			array(
				'name'         => $name,
				'default_rule' => wp_json_encode( array() ),
				'column_map'   => wp_json_encode( array() ),
				'settings'     => wp_json_encode( array() ),
				'created_at'   => current_time( 'mysql' ),
			),
			array( '%s', '%s', '%s', '%s', '%s' )
		);

		return (int) $wpdb->insert_id;
	}

	/**
	 * Persists the column map (`{ column_index: role }`) so it's proposed
	 * again on this supplier's next import.
	 *
	 * @param int   $id         Supplier id.
	 * @param array $column_map Column index => role map.
	 */
	public function save_column_map( int $id, array $column_map ): void {
		global $wpdb;
		$table = $wpdb->prefix . 'embp_suppliers';

		$wpdb->update(
			$table,
			array( 'column_map' => wp_json_encode( $column_map ) ),
			array( 'id' => $id ),
			array( '%s' ),
			array( '%d' )
		);
	}

	/**
	 * Persists the supplier's pricing rule: `{ rule: {...}, category_overrides: { "<category_id>": {...} } }`
	 * (SPEC §5). A category override fully replaces the default rule for
	 * products in that category -- it's not deep-merged with it.
	 *
	 * @param int   $id           Supplier id.
	 * @param array $default_rule The whole `{ rule, category_overrides }` structure.
	 */
	public function save_default_rule( int $id, array $default_rule ): void {
		global $wpdb;
		$table = $wpdb->prefix . 'embp_suppliers';

		$wpdb->update(
			$table,
			array( 'default_rule' => wp_json_encode( $default_rule ) ),
			array( 'id' => $id ),
			array( '%s' ),
			array( '%d' )
		);
	}

	/**
	 * Merges values into the supplier's `settings` JSON (e.g. the "prices
	 * include VAT" flag confirmed in the mapping step).
	 *
	 * @param int   $id       Supplier id.
	 * @param array $settings Values to merge into the existing settings.
	 */
	public function merge_settings( int $id, array $settings ): void {
		$supplier = $this->find( $id );

		if ( null === $supplier ) {
			return;
		}

		global $wpdb;
		$table = $wpdb->prefix . 'embp_suppliers';

		$wpdb->update(
			$table,
			array( 'settings' => wp_json_encode( array_merge( $supplier['settings'], $settings ) ) ),
			array( 'id' => $id ),
			array( '%s' ),
			array( '%d' )
		);
	}

	/**
	 * Decodes the JSON columns into arrays.
	 *
	 * @param array $row Raw database row.
	 */
	private function hydrate( array $row ): array {
		$row['default_rule'] = json_decode( (string) $row['default_rule'], true ) ?? array();
		$row['column_map']   = json_decode( (string) $row['column_map'], true ) ?? array();
		$row['settings']     = json_decode( (string) $row['settings'], true ) ?? array();

		return $row;
	}
}
