<?php
/**
 * This file is part of the Wisewand WordPress plugin.
 *
 * @package Wisewand
 * @since 1.0.0
 * @license GPL-2.0-or-later
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */
namespace Wisewand\API;

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use Wisewand\Security\Security_Manager;
use Wisewand\Content\Content_Manager;
use Wisewand\Logging\Logger;
use Wisewand\Utils\Options;

class REST_Controller extends WP_REST_Controller {

	protected $namespace = 'wisewand/v1';

	private $security_manager;
	private $content_manager;
	private $logger;
	private $options;

	public function __construct( Security_Manager $security_manager, Content_Manager $content_manager, Logger $logger, Options $options ) {
		$this->security_manager = $security_manager;
		$this->content_manager  = $content_manager;
		$this->logger           = $logger;
		$this->options          = $options;
	}

	public function register_routes() {
		// POST /publish - Main webhook endpoint for receiving content
		register_rest_route(
			$this->namespace,
			'/publish',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'publish_content' ),
				'permission_callback' => array( $this, 'check_publish_permissions' ),
				'args'                => $this->get_publish_args(),
			)
		);

		// GET /diagnose - System diagnostics (admin only)
		register_rest_route(
			$this->namespace,
			'/diagnose',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'diagnose_system' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
			)
		);

		// GET /logs - View logs (admin only)
		register_rest_route(
			$this->namespace,
			'/logs',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_logs' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => array(
					'page'     => array(
						'default'           => 1,
						'sanitize_callback' => 'absint',
					),
					'per_page' => array(
						'default'           => 20,
						'sanitize_callback' => 'absint',
					),
					'level'    => array(
						'sanitize_callback' => 'sanitize_text_field',
					),
					'search'   => array(
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
			)
		);

		// POST /pull - Pull content from Wisewand API
		register_rest_route(
			$this->namespace,
			'/pull',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'pull_content' ),
				'permission_callback' => array( $this, 'check_pull_permissions' ),
				'args'                => array(
					'article_id'   => array(
						'required'          => true,
						'sanitize_callback' => 'sanitize_text_field',
						'validate_callback' => function ( $param ) {
							return ! empty( $param );
						},
					),
					'output_index' => array(
						'default'           => 0,
						'sanitize_callback' => 'absint',
					),
				),
			)
		);

		// POST /test - Test endpoint for connectivity (admin only)
		register_rest_route(
			$this->namespace,
			'/test',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'test_connection' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
				'args'                => array(
					'test_type' => array(
						'default'           => 'ping',
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
			)
		);

		// GET /test-import/{article_id} - Test import workflow for specific article
		register_rest_route(
			$this->namespace,
			'/test-import/(?P<article_id>[a-zA-Z0-9-]+)',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'test_import_workflow' ),
				'permission_callback' => array( $this, 'check_admin_permissions' ),
			)
		);
	}

	public function check_publish_permissions( WP_REST_Request $request ) {
		// For webhook endpoint, use HMAC authentication
		$auth_result = $this->security_manager->authenticate_request( $request );

		if ( is_wp_error( $auth_result ) ) {
			$this->logger->warning(
				'Authentication failed for publish endpoint',
				array(
					'error'      => $auth_result->get_error_message(),
					'ip'         => $this->get_client_ip(),
					'user_agent' => $request->get_header( 'User-Agent' ),
				)
			);
			return $auth_result;
		}

		return true;
	}

	public function check_admin_permissions( WP_REST_Request $request ) {
		return current_user_can( 'manage_options' );
	}

	public function check_pull_permissions( WP_REST_Request $request ) {
		// Allow admin users or API key authentication
		if ( current_user_can( 'manage_options' ) ) {
			return true;
		}

		// Check for API key in header
		$api_key    = $request->get_header( 'X-Wisewand-API-Key' );
		$stored_key = $this->options->get( 'wisewand_pull_api_key' );

		if ( ! empty( $stored_key ) && hash_equals( $stored_key, $api_key ) ) {
			return true;
		}

		return new WP_Error(
			'wisewand_unauthorized',
			__( 'You do not have permission to access this endpoint.', 'wisewand-ai-content-writer-seo-content-generator' ),
			array( 'status' => 403 )
		);
	}

	public function publish_content( WP_REST_Request $request ) {
		$this->logger->info(
			'Publish request received',
			array(
				'ip'         => $this->get_client_ip(),
				'user_agent' => $request->get_header( 'User-Agent' ),
			)
		);

		try {
			// Rate limiting check
			$rate_limit_result = $this->security_manager->check_rate_limit( $request );
			if ( is_wp_error( $rate_limit_result ) ) {
				return $this->error_response( $rate_limit_result, 429 );
			}

			// Get and validate payload
			$payload = $request->get_json_params();
			if ( empty( $payload ) ) {
				return $this->error_response(
					new WP_Error( 'invalid_json', __( 'Invalid JSON payload.', 'wisewand-ai-content-writer-seo-content-generator' ) ),
					400
				);
			}

			// Process the content
			$result = $this->content_manager->process_content( $payload );

			if ( is_wp_error( $result ) ) {
				return $this->error_response( $result, 422 );
			}

			$this->logger->info(
				'Content published successfully',
				array(
					'post_id'   => $result['post_id'],
					'operation' => $result['operation'],
					'language'  => $result['language'] ?? 'default',
				)
			);

			return new WP_REST_Response(
				array(
					'success'    => true,
					'post_id'    => $result['post_id'],
					'operation'  => $result['operation'],
					'language'   => $result['language'] ?? 'default',
					'warnings'   => $result['warnings'] ?? array(),
					'request_id' => $this->logger->get_request_id(),
				),
				200
			);

		} catch ( Exception $e ) {
			$this->logger->error(
				'Unexpected error in publish endpoint',
				array(
					'error' => $e->getMessage(),
					'trace' => $e->getTraceAsString(),
				)
			);

			return $this->error_response(
				new WP_Error( 'internal_error', __( 'Internal server error.', 'wisewand-ai-content-writer-seo-content-generator' ) ),
				500
			);
		}
	}

	public function pull_content( WP_REST_Request $request ) {
		$article_id   = $request->get_param( 'article_id' );
		$output_index = $request->get_param( 'output_index' );

		$this->logger->info(
			'Pull request received',
			array(
				'article_id'   => $article_id,
				'output_index' => $output_index,
			)
		);

		try {
			$result = $this->content_manager->pull_content( $article_id, $output_index );

			if ( is_wp_error( $result ) ) {
				return $this->error_response( $result, $result->get_error_data()['status'] ?? 422 );
			}

			return new WP_REST_Response(
				array(
					'success'     => true,
					'article_id'  => $article_id,
					'status'      => $result['status'],
					'post_id'     => $result['post_id'] ?? null,
					'operation'   => $result['operation'] ?? null,
					'retry_after' => $result['retry_after'] ?? null,
					'attempts'    => $result['attempts'] ?? 0,
					'request_id'  => $this->logger->get_request_id(),
				),
				200
			);

		} catch ( Exception $e ) {
			$this->logger->error(
				'Unexpected error in pull endpoint',
				array(
					'article_id' => $article_id,
					'error'      => $e->getMessage(),
				)
			);

			return $this->error_response(
				new WP_Error( 'internal_error', __( 'Internal server error.', 'wisewand-ai-content-writer-seo-content-generator' ) ),
				500
			);
		}
	}

	public function diagnose_system( WP_REST_Request $request ) {
		// Add rate limiting to prevent abuse and information disclosure
		$rate_limit_result = $this->security_manager->check_rate_limit( $request, 'diagnose' );
		if ( is_wp_error( $rate_limit_result ) ) {
			$this->logger->warning(
				'/diagnose endpoint rate limited',
				array(
					'ip' => $this->get_client_ip(),
				)
			);
			return $this->error_response( $rate_limit_result, 429 );
		}

		// Log diagnostic access for security monitoring
		$this->logger->info(
			'/diagnose endpoint accessed',
			array(
				'ip'      => $this->get_client_ip(),
				'user_id' => get_current_user_id(),
			)
		);

		$diagnostics = array(
			'plugin_version'      => WISEWAND_PLUGIN_VERSION,
			'wordpress_version'   => get_bloginfo( 'version' ),
			'php_version'         => PHP_VERSION,
			'rest_api_enabled'    => rest_url() !== false,
			'permalinks_enabled'  => get_option( 'permalink_structure' ) !== '',
			'wp_cron_enabled'     => ! defined( 'DISABLE_WP_CRON' ) || ! DISABLE_WP_CRON,
			'memory_limit'        => ini_get( 'memory_limit' ),
			'max_execution_time'  => ini_get( 'max_execution_time' ),
			'upload_max_filesize' => ini_get( 'upload_max_filesize' ),
			'plugins'             => array(
				'yoast_seo' => $this->options->is_yoast_active(),
				'rank_math' => $this->options->is_rankmath_active(),
				'wpml'      => $this->options->is_wpml_active(),
				'seopress'  => $this->options->is_seopress_active(),
				'polylang'  => $this->options->is_polylang_active(),
			),
			'endpoints'           => array(
				'publish'  => rest_url( $this->namespace . '/publish' ),
				'diagnose' => rest_url( $this->namespace . '/diagnose' ),
				'logs'     => rest_url( $this->namespace . '/logs' ),
				'pull'     => rest_url( $this->namespace . '/pull' ),
			),
			'settings'            => array(
				'hmac_secret_configured' => ! empty( $this->options->get( 'wisewand_hmac_secret' ) ),
				'rate_limiting_enabled'  => $this->options->get( 'wisewand_rate_limit_enabled', true ),
				'logging_enabled'        => $this->options->get( 'wisewand_logging_enabled', true ),
				'debug_mode'             => $this->options->get( 'wisewand_debug_mode', false ),
			),
			'database_tables'     => $this->check_database_tables(),
			'last_cron_run'       => wp_next_scheduled( 'wisewand_cleanup_logs' ),
		);

		return new WP_REST_Response( $diagnostics, 200 );
	}

	public function get_logs( WP_REST_Request $request ) {
		$page     = $request->get_param( 'page' );
		$per_page = min( $request->get_param( 'per_page' ), 100 ); // Max 100 per request
		$level    = $request->get_param( 'level' );
		$search   = $request->get_param( 'search' );

		$offset = ( $page - 1 ) * $per_page;

		$logs  = $this->logger->get_logs( $per_page, $offset, $level, $search );
		$total = $this->logger->get_logs_count( $level, $search );

		return new WP_REST_Response(
			array(
				'logs'       => $logs,
				'pagination' => array(
					'total'        => $total,
					'pages'        => ceil( $total / $per_page ),
					'current_page' => $page,
					'per_page'     => $per_page,
				),
			),
			200
		);
	}

	public function test_connection( WP_REST_Request $request ) {
		$test_type = $request->get_param( 'test_type' );

		switch ( $test_type ) {
			case 'ping':
				return new WP_REST_Response(
					array(
						'success'    => true,
						'message'    => __( 'Wisewand plugin is responding correctly.', 'wisewand-ai-content-writer-seo-content-generator' ),
						'timestamp'  => current_time( 'mysql' ),
						'request_id' => $this->logger->get_request_id(),
					),
					200
				);

			case 'signature':
				// Test HMAC signature validation with a sample payload
				$test_payload = array( 'test' => 'data' );
				$test_body    = wp_json_encode( $test_payload );
				$secret       = $this->options->get( 'wisewand_hmac_secret' );

				if ( empty( $secret ) ) {
					return $this->error_response(
						new WP_Error( 'no_secret', __( 'HMAC secret not configured.', 'wisewand-ai-content-writer-seo-content-generator' ) ),
						400
					);
				}

				// Note: We do NOT expose the expected signature for security reasons
				// Clients should generate their own signature using their secret and compare

				return new WP_REST_Response(
					array(
						'success'          => true,
						'message'          => __( 'HMAC signature test completed.', 'wisewand-ai-content-writer-seo-content-generator' ),
						'test_payload'     => $test_payload,
						'signature_format' => __( 'sha256=[hash_hmac result]', 'wisewand-ai-content-writer-seo-content-generator' ),
						'timestamp'        => current_time( 'mysql' ),
					),
					200
				);

			default:
				return $this->error_response(
					new WP_Error( 'invalid_test', __( 'Invalid test type.', 'wisewand-ai-content-writer-seo-content-generator' ) ),
					400
				);
		}
	}

	private function get_publish_args() {
		return array(
			'external_id' => array(
				'required'          => true,
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => function ( $param ) {
					return ! empty( $param );
				},
			),
			'title'       => array(
				'sanitize_callback' => 'sanitize_text_field',
			),
			'content'     => array(
				'sanitize_callback' => array( $this, 'sanitize_content' ),
			),
			'post_type'   => array(
				'default'           => 'post',
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => array( $this, 'validate_post_type' ),
			),
			'post_status' => array(
				'default'           => 'draft',
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => array( $this, 'validate_post_status' ),
			),
			'lang'        => array(
				'sanitize_callback' => 'sanitize_text_field',
			),
		);
	}

	public function sanitize_content( $content ) {
		if ( ! class_exists( '\\Wisewand\\Utils\\Content_Cleaner' ) ) {
			require_once WISEWAND_PLUGIN_DIR . 'includes/Utils/Content_Cleaner.php';
		}

		$allowed_html = \Wisewand\Utils\Content_Cleaner::allow_audio_kses(
			wp_kses_allowed_html( 'post' ),
			'post'
		);

		return wp_kses( $content, $allowed_html );
	}

	public function validate_post_type( $param ) {
		$allowed_types = $this->options->get( 'wisewand_allowed_post_types', array( 'post', 'page' ) );
		return in_array( $param, $allowed_types, true );
	}

	public function validate_post_status( $param ) {
		$allowed_statuses = array( 'draft', 'publish', 'pending', 'future', 'private' );
		return in_array( $param, $allowed_statuses, true );
	}

	private function check_database_tables() {
		global $wpdb;

		$tables = array(
			'logs'        => $wpdb->prefix . 'wisewand_logs',
			'rate_limits' => $wpdb->prefix . 'wisewand_rate_limits',
			'pull_queue'  => $wpdb->prefix . 'wisewand_pull_queue',
		);

		$results = array();
		foreach ( $tables as $name => $table ) {
			// Use prepared statement to prevent SQL injection
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- DDL SHOW TABLES query to check table existence, not suitable for caching
			$results[ $name ] = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) === $table;
		}

		return $results;
	}

	private function error_response( WP_Error $error, $status = 400 ) {
		return new WP_REST_Response(
			array(
				'success'    => false,
				'error'      => array(
					'code'    => $error->get_error_code(),
					'message' => $error->get_error_message(),
					'data'    => $error->get_error_data(),
				),
				'request_id' => $this->logger->get_request_id(),
			),
			$status
		);
	}

	private function get_client_ip() {
		$ip_keys = array( 'HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR' );

		foreach ( $ip_keys as $key ) {
			if ( array_key_exists( $key, $_SERVER ) === true ) {
				$ip_list = explode( ',', sanitize_text_field( wp_unslash( $_SERVER[ $key ] ) ) );
				foreach ( $ip_list as $ip ) {
					$ip = trim( $ip );
					if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) ) {
						return $ip;
					}
				}
			}
		}

		return isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
	}
}
