<?php
/**
 * @package Hafenstudios\Kurato
 */

namespace Hafenstudios\Kurato\Rest;

use Hafenstudios\Kurato\Db\RecommendationRepository;
use Hafenstudios\Kurato\Insight\RecommendationEngine;

defined( 'ABSPATH' ) || exit;

/**
 * REST: Hans-Empfehlungen fuer die Cockpit-Bruecke (`kurato/v1/recommendations`
 * und `.../{id}/decide`, CP4).
 *
 * Macht die vorhandene H2-Engine zugaenglich - **keine neue Regel-Logik**:
 * {@see RecommendationEngine::evaluate()} liefert die Kandidaten,
 * {@see RecommendationRepository::record_once()} sorgt fuer den Dedup (bereits
 * entschiedene Kontexte erscheinen nie wieder, "Nicht mehr vorschlagen" wirkt
 * dauerhaft), und {@see RecommendationRepository::decide()} schreibt die
 * Entscheidung. Der globale Hans-Schalter wird respektiert: ist er aus, liefert
 * die Liste nichts.
 *
 * Rechteschnitt: Lesen hs_view_contacts, Entscheiden hs_manage_contacts. Der
 * VERSAND passiert bewusst nicht hier (UX-Konzept Kap. 5) - die App legt aus dem
 * Entwurf eine Notiz plus Wiedervorlage am Kontakt an.
 */
final class RecommendationsController extends AbstractController {

	public const REST_NAMESPACE = 'kurato/v1';

	/** Flotten-Grundsatz 4: eine Hans-Karte je Screen. Die Liste bleibt kurz. */
	private const MAX_ITEMS = 3;

	/** Wie viele Kontakt-IDs je Empfehlung mitgegeben werden (Entwurf-Anhaenger). */
	private const MAX_IDS = 20;

	private RecommendationEngine $engine;

	private RecommendationRepository $recommendations;

	private bool $hans_enabled;

	/**
	 * @param RecommendationEngine     $engine          Regel-Engine (H2).
	 * @param RecommendationRepository $recommendations Lern-Log.
	 * @param bool                     $hans_enabled    Globaler Hans-Schalter.
	 */
	public function __construct( RecommendationEngine $engine, RecommendationRepository $recommendations, bool $hans_enabled ) {
		$this->engine          = $engine;
		$this->recommendations = $recommendations;
		$this->hans_enabled    = $hans_enabled;
	}

	/**
	 * Registriert die Routen.
	 *
	 * @return void
	 */
	public function register_routes(): void {
		register_rest_route(
			self::REST_NAMESPACE,
			'/recommendations',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'list_recommendations' ),
				'permission_callback' => array( $this, 'can_view' ),
			)
		);

		register_rest_route(
			self::REST_NAMESPACE,
			'/recommendations/(?P<id>\d+)/decide',
			array(
				'methods'             => \WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'decide' ),
				'permission_callback' => array( $this, 'can_manage' ),
				'args'                => array(
					'decision' => array( 'type' => 'string', 'required' => true, 'sanitize_callback' => 'sanitize_key' ),
				),
			)
		);
	}

	/**
	 * GET /recommendations - offene Empfehlungen (dedupliziert ueber record_once).
	 *
	 * @return \WP_REST_Response
	 */
	public function list_recommendations(): \WP_REST_Response {
		if ( ! $this->hans_enabled ) {
			return new \WP_REST_Response( array( 'items' => array() ), 200 );
		}

		$items = array();
		foreach ( $this->engine->evaluate() as $candidate ) {
			if ( count( $items ) >= self::MAX_ITEMS ) {
				break;
			}
			$id = $this->recommendations->record_once( (string) $candidate['rule_key'], (string) $candidate['context_hash'] );
			if ( $id <= 0 ) {
				continue; // Bereits entschieden (oder Fehler) - Karte bleibt weg.
			}

			$action = is_array( $candidate['action'] ?? null ) ? $candidate['action'] : array();
			$ids    = is_array( $candidate['ids'] ?? null ) ? $candidate['ids'] : array();

			$items[] = array(
				'id'          => $id,
				'rule_key'    => (string) $candidate['rule_key'],
				'title'       => (string) $candidate['title'],
				'body'        => (string) $candidate['body'],
				'action'      => array(
					'intent' => (string) ( $action['intent'] ?? '' ),
					'label'  => (string) ( $action['label'] ?? '' ),
				),
				'count'       => (int) ( $candidate['count'] ?? 0 ),
				'contact_ids' => array_slice( array_map( 'intval', $ids ), 0, self::MAX_IDS ),
			);
		}

		return new \WP_REST_Response( array( 'items' => $items ), 200 );
	}

	/**
	 * POST /recommendations/{id}/decide - accepted | dismissed.
	 *
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function decide( \WP_REST_Request $request ) {
		$decision = (string) $request->get_param( 'decision' );
		if ( ! in_array( $decision, array( 'accepted', 'dismissed' ), true ) ) {
			return new \WP_Error(
				'kurato_invalid_decision',
				__( 'Bitte geben Sie accepted oder dismissed an.', 'kurato' ),
				array( 'status' => 400 )
			);
		}

		$id = (int) $request->get_param( 'id' );
		$ok = $this->recommendations->decide( $id, $decision );

		return new \WP_REST_Response(
			array(
				'ok'       => $ok,
				'id'       => $id,
				'decision' => $decision,
			),
			200
		);
	}
}
