<?php

declare(strict_types=1);

namespace FormConnector\API\Endpoints;

use FormConnector\Features\Logs\Logs;
use FormConnector\Integration\Forms\Mappings;
use FormConnector\Integration\Forms\SubmissionHandler;

/**
 * Logs REST API endpoints.
 */
class LogsEndpoints {

	private const NAMESPACE = 'fc/v1';

	/**
	 * Register logs routes.
	 */
	public static function register(): void {
		register_rest_route(self::NAMESPACE, '/logs', [
			'methods' => \WP_REST_Server::READABLE,
			'callback' => [self::class, 'get_logs'],
			'permission_callback' => [self::class, 'permission_check'],
		]);

		register_rest_route(self::NAMESPACE, '/logs/stats', [
			'methods' => \WP_REST_Server::READABLE,
			'callback' => [self::class, 'get_stats'],
			'permission_callback' => [self::class, 'permission_check'],
		]);

		register_rest_route(self::NAMESPACE, '/logs/(?P<id>\d+)', [
			'methods' => \WP_REST_Server::READABLE,
			'callback' => [self::class, 'get_log'],
			'permission_callback' => [self::class, 'permission_check'],
		]);

		register_rest_route(self::NAMESPACE, '/logs/(?P<id>\d+)', [
			'methods' => \WP_REST_Server::DELETABLE,
			'callback' => [self::class, 'delete_log'],
			'permission_callback' => [self::class, 'permission_check'],
		]);

		register_rest_route(self::NAMESPACE, '/logs/clear', [
			'methods' => \WP_REST_Server::CREATABLE,
			'callback' => [self::class, 'clear_logs'],
			'permission_callback' => [self::class, 'permission_check'],
		]);

		register_rest_route(self::NAMESPACE, '/logs/export', [
			'methods' => \WP_REST_Server::READABLE,
			'callback' => [self::class, 'export_csv'],
			'permission_callback' => [self::class, 'permission_check'],
		]);

		register_rest_route(self::NAMESPACE, '/logs/(?P<id>\d+)/replay', [
			'methods' => \WP_REST_Server::CREATABLE,
			'callback' => [self::class, 'replay_log'],
			'permission_callback' => [self::class, 'permission_check'],
		]);

		register_rest_route(self::NAMESPACE, '/logs/(?P<id>\d+)/diagnose', [
			'methods' => \WP_REST_Server::READABLE,
			'callback' => [self::class, 'diagnose_log'],
			'permission_callback' => [self::class, 'permission_check'],
		]);
	}

	/**
	 * Replay a stored submission against the current mapping.
	 *
	 * Currently dry-run only: returns the payload that *would* be sent to
	 * CareHQ if the original submission were re-processed today.
	 */
	public static function replay_log(\WP_REST_Request $request): \WP_REST_Response {
		$id = (int) $request->get_param('id');
		$dry_run = filter_var($request->get_param('dry_run'), FILTER_VALIDATE_BOOLEAN);

		// Hard-gate: only dry-run replay is supported in v3.6.
		if (!$dry_run) {
			return new \WP_REST_Response([
				'success' => false,
				'message' => __('Only dry-run replay is supported. Pass dry_run=true.', 'form-connector'),
			], 400);
		}

		$log = Logs::get_instance()->get_log($id);
		if (!$log) {
			return new \WP_REST_Response([
				'success' => false,
				'message' => __('Log entry not found.', 'form-connector'),
			], 404);
		}

		$plugin = (string) ($log['form_plugin'] ?? '');
		$form_id = (string) ($log['form_id'] ?? '');
		$submitted = $log['submitted_data'] ?? [];
		$original_fields = is_array($submitted['original_fields'] ?? null)
			? $submitted['original_fields']
			: (is_array($submitted) ? $submitted : []);
		$previous_payload = is_array($submitted['mapped_to_carehq'] ?? null)
			? $submitted['mapped_to_carehq']
			: [];

		if (empty($plugin) || $form_id === '' || empty($original_fields)) {
			return new \WP_REST_Response([
				'success' => false,
				'message' => __('Stored submission is missing the data required to replay.', 'form-connector'),
			], 422);
		}

		$mapping = Mappings::get_instance()->get_mapping($plugin, $form_id);
		$field_mapping = $mapping['fields'] ?? [];

		if (empty($field_mapping)) {
			return new \WP_REST_Response([
				'success' => false,
				'message' => __('No mapping is configured for this form. Configure mappings before replaying.', 'form-connector'),
			], 422);
		}

		$proposed = SubmissionHandler::get_instance()->map_fields($original_fields, $field_mapping);

		// Diff: keys added / removed / changed vs. the previously-sent payload.
		$diff = [
			'added'   => array_values(array_diff(array_keys($proposed), array_keys($previous_payload))),
			'removed' => array_values(array_diff(array_keys($previous_payload), array_keys($proposed))),
			'changed' => [],
		];
		foreach ($proposed as $k => $v) {
			if (array_key_exists($k, $previous_payload) && (string) $previous_payload[$k] !== (string) $v) {
				$diff['changed'][] = $k;
			}
		}

		return new \WP_REST_Response([
			'success' => true,
			'data' => [
				'dry_run' => true,
				'log_id' => $id,
				'plugin' => $plugin,
				'form_id' => $form_id,
				'previous_payload' => $previous_payload,
				'proposed_payload' => $proposed,
				'diff' => $diff,
			],
		], 200);
	}

	/**
	 * Permission check for admin-only endpoints.
	 */
	public static function permission_check(): bool {
		return current_user_can('manage_options');
	}

	/**
	 * Get logs with filtering and pagination.
	 */
	public static function get_logs(\WP_REST_Request $request): \WP_REST_Response {
		$logs = Logs::get_instance();

		$args = [
			'page'      => (int) ($request->get_param('page') ?? 1),
			'per_page'  => (int) ($request->get_param('per_page') ?? 20),
			'status'    => sanitize_text_field($request->get_param('status') ?? ''),
			'plugin'    => sanitize_text_field($request->get_param('plugin') ?? ''),
			'search'    => sanitize_text_field($request->get_param('search') ?? ''),
			'date_from' => sanitize_text_field($request->get_param('date_from') ?? ''),
			'date_to'   => sanitize_text_field($request->get_param('date_to') ?? ''),
			'orderby'   => sanitize_text_field($request->get_param('orderby') ?? 'timestamp'),
			'order'     => sanitize_text_field($request->get_param('order') ?? 'DESC'),
		];

		$result = $logs->get_logs($args);

		return new \WP_REST_Response([
			'success' => true,
			'data' => $result,
		], 200);
	}

	/**
	 * Get log statistics.
	 */
	public static function get_stats(\WP_REST_Request $request): \WP_REST_Response {
		$logs = Logs::get_instance();

		return new \WP_REST_Response([
			'success' => true,
			'data' => $logs->get_stats(),
		], 200);
	}

	/**
	 * Get a single log entry.
	 */
	public static function get_log(\WP_REST_Request $request): \WP_REST_Response {
		$id = (int) $request->get_param('id');
		$logs = Logs::get_instance();
		$log = $logs->get_log($id);

		if (!$log) {
			return new \WP_REST_Response([
				'success' => false,
				'message' => __('Log entry not found.', 'form-connector'),
			], 404);
		}

		return new \WP_REST_Response([
			'success' => true,
			'data' => $log,
		], 200);
	}

	/**
	 * Delete a log entry.
	 */
	public static function delete_log(\WP_REST_Request $request): \WP_REST_Response {
		$id = (int) $request->get_param('id');
		$logs = Logs::get_instance();
		$deleted = $logs->delete_log($id);

		if (!$deleted) {
			return new \WP_REST_Response([
				'success' => false,
				'message' => __('Failed to delete log entry.', 'form-connector'),
			], 500);
		}

		return new \WP_REST_Response([
			'success' => true,
			'message' => __('Log entry deleted.', 'form-connector'),
		], 200);
	}

	/**
	 * Clear all logs.
	 */
	public static function clear_logs(\WP_REST_Request $request): \WP_REST_Response {
		$logs = Logs::get_instance();
		$cleared = $logs->clear_all();

		if (!$cleared) {
			return new \WP_REST_Response([
				'success' => false,
				'message' => __('Failed to clear logs.', 'form-connector'),
			], 500);
		}

		return new \WP_REST_Response([
			'success' => true,
			'message' => __('All logs cleared.', 'form-connector'),
		], 200);
	}

	/**
	 * Export logs as CSV data (returns JSON with CSV content).
	 */
	public static function export_csv(\WP_REST_Request $request): \WP_REST_Response {
		$logs = Logs::get_instance();

		$args = [
			'page'      => 1,
			'per_page'  => 10000,
			'status'    => sanitize_text_field($request->get_param('status') ?? ''),
			'plugin'    => sanitize_text_field($request->get_param('plugin') ?? ''),
			'search'    => sanitize_text_field($request->get_param('search') ?? ''),
			'date_from' => sanitize_text_field($request->get_param('date_from') ?? ''),
			'date_to'   => sanitize_text_field($request->get_param('date_to') ?? ''),
			'orderby'   => 'timestamp',
			'order'     => 'DESC',
		];

		$result = $logs->get_logs($args);
		$entries = $result['logs'] ?? [];

		// Build CSV
		$csv_lines = [];

		// Header
		$csv_lines[] = self::csv_row([
			'ID', 'Date', 'Form Name', 'Form Plugin', 'Status',
			'Location', 'First Name', 'Last Name', 'Email', 'Phone',
			'UTM Source', 'UTM Medium', 'UTM Campaign', 'UTM Term', 'UTM Content',
			'Landing Page', 'Referrer',
		]);

		foreach ($entries as $entry) {
			$mapped = [];
			$submitted = $entry['submitted_data'] ?? [];
			if (isset($submitted['mapped_to_carehq'])) {
				$mapped = $submitted['mapped_to_carehq'];
			}

			$csv_lines[] = self::csv_row([
				$entry['id'] ?? '',
				$entry['timestamp'] ?? '',
				$entry['form_name'] ?? '',
				$entry['form_plugin'] ?? '',
				$entry['response_status'] ?? '',
				$entry['location_name'] ?? '',
				$mapped['first_name'] ?? '',
				$mapped['last_name'] ?? '',
				$mapped['email'] ?? '',
				$mapped['phone'] ?? '',
				$entry['utm_source'] ?? '',
				$entry['utm_medium'] ?? '',
				$entry['utm_campaign'] ?? '',
				$entry['utm_term'] ?? '',
				$entry['utm_content'] ?? '',
				$entry['landing_page'] ?? '',
				$entry['referrer_other'] ?? '',
			]);
		}

		$csv_content = implode("\n", $csv_lines);

		return new \WP_REST_Response([
			'success' => true,
			'data' => [
				'csv' => $csv_content,
				'filename' => 'carehq-submissions-' . gmdate('Y-m-d') . '.csv',
				'count' => count($entries),
			],
		], 200);
	}

	/**
	 * Convert an array of values to a CSV row string.
	 */
	private static function csv_row(array $fields): string {
		$escaped = array_map(function ($field) {
			$field = str_replace('"', '""', (string) $field);
			return '"' . $field . '"';
		}, $fields);
		return implode(',', $escaped);
	}

	// -------------------------------------------------------------------------
	// Diagnose
	// -------------------------------------------------------------------------

	/**
	 * Return a human-readable diagnosis for a failed or blocked log entry.
	 */
	public static function diagnose_log(\WP_REST_Request $request): \WP_REST_Response {
		$id  = (int) $request->get_param('id');
		$log = Logs::get_instance()->get_log($id);

		if (!$log) {
			return new \WP_REST_Response([
				'success' => false,
				'message' => __('Log entry not found.', 'form-connector'),
			], 404);
		}

		$status         = (string) ($log['response_status'] ?? '');
		$submitted_data = is_array($log['submitted_data'])  ? $log['submitted_data']  : [];
		$response_msg   = is_array($log['response_message']) ? $log['response_message'] : [];

		$diagnosis = self::analyse_log_error($status, $submitted_data, $response_msg);

		return new \WP_REST_Response([
			'success' => true,
			'data'    => $diagnosis,
		], 200);
	}

	/**
	 * Translate raw error data into a structured, human-readable diagnosis.
	 *
	 * @param string $status         The log's response_status value.
	 * @param array  $submitted_data The decoded submitted_data JSON column.
	 * @param array  $response_msg   The decoded response_message JSON column.
	 * @return array{title:string, description:string, suggestions:string[], severity:string}
	 */
	private static function analyse_log_error(string $status, array $submitted_data, array $response_msg): array {
		$error_text   = is_string($submitted_data['error'] ?? null)          ? (string) $submitted_data['error']          : '';
		$error_code   = is_string($response_msg['error_code'] ?? null)        ? (string) $response_msg['error_code']        : '';
		$error_msg    = is_string($response_msg['error_message'] ?? null)     ? (string) $response_msg['error_message']     : '';
		$resp_error   = is_string($response_msg['error'] ?? null)             ? (string) $response_msg['error']             : '';
		$full_error   = $error_text ?: $error_msg ?: $resp_error;

		// License issues
		if (str_contains(strtolower($full_error), 'license') || str_contains($error_code, 'license')) {
			return [
				'title'       => __('License issue', 'form-connector'),
				'description' => __('Your FormConnector license may be inactive, expired, or invalid. Submissions are blocked until the license is resolved.', 'form-connector'),
				'suggestions' => [
					__('Go to Settings → License and verify your license key is active.', 'form-connector'),
					__('If you recently changed hosting or domain, re-activate the license key.', 'form-connector'),
				],
				'severity'    => 'critical',
			];
		}

		// No location configured
		if (str_contains($full_error, 'No location configured')) {
			return [
				'title'       => __('No location configured', 'form-connector'),
				'description' => __('No CareHQ home was selected for this form. Submissions cannot be routed without a target location.', 'form-connector'),
				'suggestions' => [
					__('Go to Mappings, select this form, and choose a location under the Settings tab.', 'form-connector'),
					__('Alternatively, configure Conditional Routing rules that cover all possible field values.', 'form-connector'),
				],
				'severity'    => 'error',
			];
		}

		// Home not registered / seat limit
		if (str_contains($full_error, 'Home is not registered') || str_contains($full_error, 'seat limit')) {
			return [
				'title'       => __('Home not registered with license', 'form-connector'),
				'description' => __('The CareHQ home this form routes to is not linked to your license, or you have exceeded your paid seat limit.', 'form-connector'),
				'suggestions' => [
					__('Go to Settings → Homes and add this home to your license.', 'form-connector'),
					__('If you have reached your seat limit, remove an unused home or upgrade your subscription.', 'form-connector'),
				],
				'severity'    => 'error',
			];
		}

		// No fields could be mapped
		if (str_contains($full_error, 'No fields could be mapped')) {
			$available_keys = is_array($submitted_data['available_keys'] ?? null)
				? $submitted_data['available_keys']
				: [];

			$desc = __('None of the form field IDs in the mapping matched the fields received from the submission. The form may have been edited since the mapping was last saved.', 'form-connector');
			if (!empty($available_keys)) {
				$desc .= ' ' . sprintf(
					/* translators: %s: comma-separated list of field IDs */
					__('Received field IDs: %s.', 'form-connector'),
					implode(', ', array_slice($available_keys, 0, 10))
				);
			}

			return [
				'title'       => __('Field mapping mismatch', 'form-connector'),
				'description' => $desc,
				'suggestions' => [
					__('Go to Mappings, select this form, and re-map each field — field IDs may have changed.', 'form-connector'),
					__('Use the "Auto-suggest" button on the Field Mappings tab to re-suggest fields automatically.', 'form-connector'),
				],
				'severity'    => 'error',
			];
		}

		// Sales channel not configured
		if (str_contains($full_error, 'Sales Channel is not configured') || str_contains($full_error, 'sales_channel')) {
			return [
				'title'       => __('Sales Channel not configured', 'form-connector'),
				'description' => __('A Sales Channel ID is required by the CareHQ API but has not been configured in the plugin settings.', 'form-connector'),
				'suggestions' => [
					__('Go to Settings → CareHQ API and enter your Sales Channel ID.', 'form-connector'),
					__('Find the Sales Channel ID in your CareHQ account under Settings → Sales Channels.', 'form-connector'),
				],
				'severity'    => 'error',
			];
		}

		// Network / HTTP request failed
		if ($error_code === 'http_request_failed') {
			return [
				'title'       => __('Network error', 'form-connector'),
				'description' => sprintf(
					/* translators: %s: error message from WordPress HTTP layer */
					__('WordPress could not reach the CareHQ API. Error: %s', 'form-connector'),
					$error_msg ?: __('(no details)', 'form-connector')
				),
				'suggestions' => [
					__('Check that your server allows outbound HTTPS connections to api.carehq.co.uk.', 'form-connector'),
					__('If you are on a local/staging environment, the CareHQ API may not be reachable from there.', 'form-connector'),
					__('Contact your hosting provider if outbound connections are blocked.', 'form-connector'),
				],
				'severity'    => 'error',
			];
		}

		// CareHQ authentication failure
		if (str_contains($error_msg, '401') || str_contains($error_msg, '403') || str_contains($error_code, 'auth')) {
			return [
				'title'       => __('CareHQ authentication failed', 'form-connector'),
				'description' => __('CareHQ returned an authentication error. The API credentials may be invalid or expired.', 'form-connector'),
				'suggestions' => [
					__('Go to Settings → CareHQ API and verify your API Key and Secret.', 'form-connector'),
					__('Regenerate your API credentials in your CareHQ account if they have been rotated.', 'form-connector'),
				],
				'severity'    => 'critical',
			];
		}

		// CareHQ validation / unprocessable
		if ($error_code === 'carehq_api_error' || str_contains($error_msg, '422') || str_contains(strtolower($error_msg), 'unprocessable')) {
			return [
				'title'       => __('CareHQ rejected the submission', 'form-connector'),
				'description' => sprintf(
					/* translators: %s: CareHQ API error details */
					__('CareHQ returned a validation error for this submission. Details: %s', 'form-connector'),
					$error_msg ?: __('(no details available)', 'form-connector')
				),
				'suggestions' => [
					__('Ensure at least an email address or phone number is mapped and present in the submission.', 'form-connector'),
					__('Verify the phone number is in valid UK E.164 format (e.g. +447700900000).', 'form-connector'),
					__('Check the location ID is correct in your CareHQ account.', 'form-connector'),
				],
				'severity'    => 'error',
			];
		}

		// Rate limit
		if (str_contains($error_msg, '429') || str_contains($error_code, 'rate_limit')) {
			return [
				'title'       => __('CareHQ rate limit reached', 'form-connector'),
				'description' => __('Your CareHQ account hit the API rate limit at the time of this submission.', 'form-connector'),
				'suggestions' => [
					__('Wait a few minutes and retry using the Replay button.', 'form-connector'),
					__('Contact CareHQ support if you are consistently hitting rate limits.', 'form-connector'),
				],
				'severity'    => 'warning',
			];
		}

		// Blocked without specific pattern
		if ($status === 'blocked') {
			return [
				'title'       => __('Submission blocked', 'form-connector'),
				'description' => $full_error ?: __('The submission was blocked before reaching CareHQ.', 'form-connector'),
				'suggestions' => [
					__('Review your license, location configuration, and home registration settings.', 'form-connector'),
				],
				'severity'    => 'warning',
			];
		}

		// Generic fallback
		return [
			'title'       => __('Submission error', 'form-connector'),
			'description' => $full_error ?: __('An unknown error occurred. Check the raw response data below for more details.', 'form-connector'),
			'suggestions' => [
				__('Review the "Response" section in this log entry for the raw error from CareHQ.', 'form-connector'),
				__('Check your PHP error log for additional details.', 'form-connector'),
			],
			'severity'    => 'error',
		];
	}
}
