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

namespace Hafenstudios\Kurato\Rest;

use Hafenstudios\Kurato\Campaign\SegmentDefinition;
use Hafenstudios\Kurato\Campaign\SegmentQuery;
use Hafenstudios\Kurato\Db\SegmentRepository;

defined( 'ABSPATH' ) || exit;

/**
 * REST: Segmente (`kurato/v1/segments`, K4-Konzept Abschnitt 4).
 *
 * CRUD auf gespeicherten Filtern plus ein Vorschau-Zaehler fuer den Live-Wert im
 * Segment-Builder. Lesen ueber hs_view_contacts, Schreiben ueber hs_manage_contacts
 * (Muster TagsController/AbstractController).
 */
final class SegmentsController extends AbstractController {

	public const REST_NAMESPACE = 'kurato/v1';

	private SegmentRepository $segments;

	private SegmentQuery $query;

	/**
	 * @param SegmentRepository $segments Segment-Repository.
	 * @param SegmentQuery      $query    Segment-Auswertung (Vorschau-Zaehler).
	 */
	public function __construct( SegmentRepository $segments, SegmentQuery $query ) {
		$this->segments = $segments;
		$this->query    = $query;
	}

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

		register_rest_route(
			self::REST_NAMESPACE,
			'/segments/(?P<id>\d+)',
			array(
				array(
					'methods'             => \WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'update_segment' ),
					'permission_callback' => array( $this, 'can_manage' ),
				),
				array(
					'methods'             => \WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_segment' ),
					'permission_callback' => array( $this, 'can_manage' ),
				),
			)
		);

		register_rest_route(
			self::REST_NAMESPACE,
			'/segments/preview-count',
			array(
				'methods'             => \WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'preview_count' ),
				'permission_callback' => array( $this, 'can_view' ),
			)
		);
	}

	/**
	 * GET /segments.
	 *
	 * @return \WP_REST_Response
	 */
	public function list_segments(): \WP_REST_Response {
		return new \WP_REST_Response( $this->segments->all(), 200 );
	}

	/**
	 * POST /segments.
	 *
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function create_segment( \WP_REST_Request $request ) {
		$label = trim( sanitize_text_field( (string) $request->get_param( 'label' ) ) );
		if ( '' === $label ) {
			return $this->invalid_label();
		}
		$id = $this->segments->create( $label, $request->get_param( 'definition' ) );
		if ( $id <= 0 ) {
			return new \WP_Error( 'kurato_segment_failed', __( 'Das Segment konnte nicht gespeichert werden.', 'kurato' ), array( 'status' => 500 ) );
		}
		return new \WP_REST_Response( $this->segments->get( $id ), 201 );
	}

	/**
	 * PUT /segments/{id}.
	 *
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function update_segment( \WP_REST_Request $request ) {
		$id = (int) $request->get_param( 'id' );
		if ( null === $this->segments->get( $id ) ) {
			return $this->not_found();
		}

		$data = array();
		if ( null !== $request->get_param( 'label' ) ) {
			$data['label'] = (string) $request->get_param( 'label' );
		}
		if ( null !== $request->get_param( 'definition' ) ) {
			$data['definition'] = $request->get_param( 'definition' );
		}
		if ( array() !== $data ) {
			$this->segments->update( $id, $data );
		}
		return new \WP_REST_Response( $this->segments->get( $id ), 200 );
	}

	/**
	 * DELETE /segments/{id}.
	 *
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function delete_segment( \WP_REST_Request $request ) {
		$id = (int) $request->get_param( 'id' );
		if ( null === $this->segments->get( $id ) ) {
			return $this->not_found();
		}
		$this->segments->delete( $id );
		return new \WP_REST_Response( array( 'deleted' => true, 'id' => $id ), 200 );
	}

	/**
	 * POST /segments/preview-count - Trefferzahl einer (noch ungespeicherten)
	 * Definition fuer den Live-Zaehler.
	 *
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response
	 */
	public function preview_count( \WP_REST_Request $request ): \WP_REST_Response {
		$definition = SegmentDefinition::sanitize( $request->get_param( 'definition' ) );
		$count      = $this->query->count( $definition );
		return new \WP_REST_Response( array( 'count' => $count ), 200 );
	}

	/**
	 * @return \WP_Error
	 */
	private function invalid_label() {
		return new \WP_Error(
			'kurato_segment_label',
			__( 'Bitte geben Sie dem Segment einen Namen.', 'kurato' ),
			array( 'status' => 400 )
		);
	}

	/**
	 * @return \WP_Error
	 */
	private function not_found() {
		return new \WP_Error(
			'kurato_segment_not_found',
			__( 'Das Segment wurde nicht gefunden.', 'kurato' ),
			array( 'status' => 404 )
		);
	}
}
