<?php

namespace Formatrica\REST;

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

use Formatrica\Forms\Form_Repository;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

final class Form_Controller extends Base_Rest_Controller implements Rest_Controller
{
    // Inherit namespace from Base_Rest_Controller

    private Form_Repository $repository;

    public function __construct(?Form_Repository $repository = null)
    {
        $this->repository = $repository ?? new Form_Repository();
    }

    public function register_routes(): void
    {
        register_rest_route(
            self::NAMESPACE,
            '/forms',
            [
                'args' => $this->get_collection_params(),
                [
                    'methods' => \WP_REST_Server::READABLE,
                    'callback' => [$this, 'list_forms'],
                    'permission_callback' => [$this, 'permissions_check'],
                ],
                [
                    'methods' => \WP_REST_Server::CREATABLE,
                    'callback' => [$this, 'create_form'],
                    'permission_callback' => [$this, 'permissions_check'],
                    'args' => $this->get_collection_params(),
                ],
            ]
        );

        register_rest_route(
            self::NAMESPACE,
            '/forms/(?P<form_id>\\d+)',
            [
                'args' => $this->get_item_args(),
                [
                    'methods' => \WP_REST_Server::READABLE,
                    'callback' => [$this, 'get_form'],
                    'permission_callback' => [$this, 'permissions_check'],
                ],
                [
                    'methods' => \WP_REST_Server::EDITABLE,
                    'callback' => [$this, 'update_form'],
                    'permission_callback' => [$this, 'permissions_check'],
                    'args' => $this->get_collection_params(),
                ],
                [
                    'methods' => \WP_REST_Server::DELETABLE,
                    'callback' => [$this, 'delete_form'],
                    'permission_callback' => [$this, 'permissions_check'],
                ],
            ]
        );
    }

    public function list_forms(WP_REST_Request $request): WP_REST_Response
    {
        return new WP_REST_Response([
            'forms' => $this->repository->all(),
        ]);
    }

    public function create_form(WP_REST_Request $request): WP_REST_Response
    {
        try {
            $payload = $this->extract_payload($request);
            $form = $this->repository->save(null, $payload);
        } catch (\Throwable $e) {
            return $this->error_response($e);
        }

        return new WP_REST_Response($form, 201);
    }

    public function get_form(WP_REST_Request $request): WP_REST_Response
    {
        $form_id = $this->get_form_id($request);
        $form = $this->repository->get($form_id);

        if (null === $form) {
            return new WP_REST_Response([
                'message' => __('Form not found.', 'formatrica'),
            ], 404);
        }

        return new WP_REST_Response($form);
    }

    public function update_form(WP_REST_Request $request): WP_REST_Response
    {
        $form_id = $this->get_form_id($request);

        try {
            $payload = $this->extract_payload($request);
            $form = $this->repository->save($form_id, $payload);
        } catch (\Throwable $e) {
            return $this->error_response($e);
        }

        return new WP_REST_Response($form);
    }

    public function delete_form(WP_REST_Request $request): WP_REST_Response
    {
        $form_id = $this->get_form_id($request);
        $deleted = $this->repository->delete($form_id);

        if (!$deleted) {
            return new WP_REST_Response([
                'message' => __('Form could not be deleted.', 'formatrica'),
            ], 500);
        }

        return new WP_REST_Response(null, 204);
    }

    /**
     * @return bool|WP_Error
     */
    public function permissions_check(WP_REST_Request $request)
    {
        return parent::permissions_check($request);
    }

    private function extract_payload(WP_REST_Request $request): array
    {
        $nonce_check = $this->verify_rest_nonce_or_error($request);
        if ($nonce_check instanceof WP_Error) {
            throw new \RuntimeException(sanitize_text_field($nonce_check->get_error_message()), (int) ($nonce_check->get_error_data('status') ?: 403)); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
        }

        $title = $request->get_param('title');
        $config = $request->get_param('config');

        return [
            'title' => is_string($title) ? $title : '',
            'config' => is_array($config) ? $config : [],
        ];
    }

    /**
     * Validate form ID from request.
     */
    private function get_form_id(WP_REST_Request $request): int
    {
        return max(0, (int) $request->get_param('form_id'));
    }

    /**
     * @param \Throwable|WP_Error $error
     */
    private function error_response($error): WP_REST_Response
    {
        $message = $error instanceof WP_Error ? $error->get_error_message() : $error->getMessage();
        $status = 500;

        if ($error instanceof WP_Error) {
            $status = $error->get_error_data('status') ?: 500;
        } elseif ($error instanceof \Throwable && $error->getCode() > 0) {
            $status = (int) $error->getCode();
        }

        return new WP_REST_Response([
            'message' => $message ?: __('Unexpected error.', 'formatrica'),
        ], $status);
    }

    /**
     * Define schema for collection endpoints.
     *
     * @return array<string, array<string, mixed>>
     */
    private function get_collection_params(): array
    {
        return [
            'title' => [
                'description' => __('Form title.', 'formatrica'),
                'type' => 'string',
                'required' => false,
                'sanitize_callback' => 'sanitize_text_field',
            ],
            'config' => [
                'description' => __('Form configuration payload.', 'formatrica'),
                'type' => 'object',
                'required' => false,
                'sanitize_callback' => [$this, 'sanitize_config_param'],
                'validate_callback' => [$this, 'validate_config_param'],
            ],
        ];
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    private function get_item_args(): array
    {
        return [
            'form_id' => [
                'description' => __('Numeric form identifier.', 'formatrica'),
                'type' => 'integer',
                'required' => true,
                'sanitize_callback' => 'absint',
                'validate_callback' => static function ($value): bool {
                    return is_numeric($value) && (int) $value >= 0;
                },
            ],
        ];
    }

    /**
     * @param mixed $value
     */
    public function sanitize_config_param($value): array
    {
        return is_array($value) ? $value : [];
    }

    /**
     * @param mixed $value
     */
    public function validate_config_param($value): bool
    {
        return is_array($value);
    }
}
