<?php
/**
 * Supplier REST API Controller
 *
 * @category   WordPress_Plugin
 * @package    Common
 * @subpackage Controllers\Rest_API
 * @author     miniOrange <info@miniorange.com>
 * @license    MIT/Expat
 * @link       https://plugins.miniorange.com/woocommerce-api-product-sync-with-woocommerce-rest-apis
 */

namespace MOWCPS\Common\Controllers\Rest_API;

use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use MOWCPS\Common\Abstracts\Base_Rest_Controller;
use MOWCPS\Common\Handlers\Rest_API\Supplier_Handler;
use MOWCPS\Common\Utils\Response_Builder;
use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Services\Export_Supplier\Export_Supplier;
use MOWCPS\Common\Handlers\File_Save_Handler\File_Save_Handler;
use MOWCPS\Common\Utils\Utils;
use MOWCPS\Common\Services\Auditing\Supplier_Audit_Logger;
use MOWCPS\Common\Models\Supplier_Model;
use MOWCPS\Common\Models\Product_Sync_Audit_Model;

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

/**
 * Class Supplier_Rest_Controller
 *
 * Handles supplier REST API callbacks
 */
class Supplier_Rest_Controller extends Base_Rest_Controller {
	/**
	 * Handler instance
	 *
	 * @var Supplier_Handler
	 */
	private $handler;

	/**
	 * Constructor
	 */
	public function __construct() {
		$this->handler = new Supplier_Handler();
	}

	/**
	 * Get all items
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function get_items( $request ) {
		$result = $this->handler->get_all( array( 'columns' => $request->get_param( 'columns' ) ) );
		if ( is_wp_error( $result ) ) {
			return Response_Builder::from_wp_error( $result );
		}

		return Response_Builder::success( $result );
	}

	/**
	 * Bulk create item
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function import_bulk_supplier( $request ) {
		$request_data = $request->get_json_params();

		if ( empty( $request_data ) || ! is_array( $request_data ) ) {
			return Response_Builder::error(
				'invalid_payload',
				'Request body must be a JSON object with "data" and optional "overwrite_if_exist" fields.',
				400
			);
		}

		$overwrite_if_exist = isset( $request_data['overwrite_if_exist'] ) && (bool) $request_data['overwrite_if_exist'];
		if ( ! isset( $request_data['data'] ) ) {
			return Response_Builder::error(
				'missing_data_field',
				'Request body must contain a "data" field with supplier data.',
				400
			);
		}

		$data_string = $request_data['data'];

		if ( is_string( $data_string ) ) {
			$data = json_decode( $data_string, true );
			if ( json_last_error() !== JSON_ERROR_NONE ) {
				return Response_Builder::error(
					'invalid_json_data',
					'Invalid JSON in "data" field: ' . json_last_error_msg(),
					400
				);
			}
		} elseif ( is_array( $data_string ) ) {
			$data = $data_string;
		} else {
			return Response_Builder::error(
				'invalid_data_type',
				'"data" field must be a JSON string or array of suppliers.',
				400
			);
		}

		if ( empty( $data ) || ! is_array( $data ) ) {
			return Response_Builder::error(
				'invalid_data',
				'"data" must be a non-empty array of suppliers.',
				400
			);
		}

		$payload = $this->handler->create_bulk_suppliers( $data, $overwrite_if_exist );

		return Response_Builder::success( $payload );
	}

	/**
	 * Export bulk suppliers
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function export_bulk_suppliers( $request ) {
		$data = $request->get_json_params();

		if ( empty( $data ) || ! is_array( $data ) ) {
			return Response_Builder::error(
				'invalid_payload',
				'Request body must be a JSON object with supplier_ids array.',
				400
			);
		}

		$export_supplier_service = new Export_Supplier();
		$response                = $export_supplier_service->export_supplier( $data );

		return $response;
	}

	/**
	 * Create item
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function create_item( $request ) {
		$data = $request->get_json_params();

		// Check if app_type is custom or default.
		$app_type = $data['app_type'] ?? '';

		if ( Constants::SUPPLIER_APP_TYPE_CUSTOM === $app_type ) {
			// For custom suppliers, use existing handler logic.
			$item = $this->handler->create( $data );
			if ( is_wp_error( $item ) ) {
				return Response_Builder::from_wp_error( $item );
			}

			return Response_Builder::success( $item, 201 );
		}

		// For default app types, delegate to supplier app class.
		$namespace            = false !== strpos( Constants::MOWCPS_PLAN_NAME, 'standard' ) ? 'Common' : MOWCPS_PLAN_NAMESPACE;
		$supplier_app_factory = 'MOWCPS\\' . $namespace . '\\Factories\\Supplier_App_Factory';
		$supplier_app         = $supplier_app_factory::create_supplier_app( $app_type );
		if ( is_wp_error( $supplier_app ) ) {
			return Response_Builder::from_wp_error( $supplier_app );
		}

		// Delegate the entire creation process to the supplier app.
		$item = $supplier_app->create_supplier( $data );
		if ( is_wp_error( $item ) ) {
			return Response_Builder::from_wp_error( $item );
		}

		return Response_Builder::success( $item, 201 );
	}

	/**
	 * Update item
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function update_item( $request ) {
		$supplier_uuid = sanitize_key( wp_unslash( $request->get_param( 'supplier_uuid' ) ) );
		$data          = $request->get_json_params();

		$item = $this->handler->update( $supplier_uuid, $data );

		if ( is_wp_error( $item ) ) {
			return Response_Builder::from_wp_error( $item );
		}

		return Response_Builder::success( $item );
	}

	/**
	 * Get item by UUID
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function get_item( $request ) {
		$supplier_uuid = sanitize_key( wp_unslash( $request->get_param( 'supplier_uuid' ) ) );
		$item          = $this->handler->get_by_uuid( $supplier_uuid );

		if ( is_wp_error( $item ) ) {
			return Response_Builder::from_wp_error( $item );
		}

		return Response_Builder::success( $item );
	}

	/**
	 * Delete item
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function delete_item( $request ) {
		$supplier_uuid = sanitize_key( wp_unslash( $request->get_param( 'supplier_uuid' ) ) );
		$result        = $this->handler->delete( $supplier_uuid );

		if ( is_wp_error( $result ) ) {
			return Response_Builder::from_wp_error( $result );
		}

		return Response_Builder::deleted();
	}

	/**
	 * Test supplier connection configuration
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function test_supplier( $request ) {
		$data = $request->get_json_params();

		// Validate required supplier data.
		if ( empty( $data['app_type'] ) ) {
			return Response_Builder::error(
				'invalid_supplier_data',
				'Supplier app type is required for testing.',
				400
			);
		}

		if ( empty( $data['details'] ) ) {
			return Response_Builder::error(
				'invalid_supplier_data',
				'Supplier details are required for testing.',
				400
			);
		}

		$supplier_data = array(
			'app_type' => sanitize_text_field( $data['app_type'] ),
			'details'  => $data['details'],
		);

		$result = $this->handler->test_supplier( $supplier_data );

		if ( is_wp_error( $result ) ) {
			return Response_Builder::from_wp_error( $result );
		}

		$status_code = $result['status_code'];

		if ( $status_code >= 200 && $status_code < 300 ) {
			return Response_Builder::success( $result['data'], $status_code );
		}

		return Response_Builder::error(
			Constants::NOT_2XX_API_RESPONSE,
			$result,
			$status_code
		);
	}

	/**
	 * Get SNS Activewear payment profiles
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function get_payment_profiles( $request ) {
		$data = $request->get_json_params();

		// Get supplier_uuid from URL path parameter.
		$supplier_uuid = sanitize_key( $request->get_param( 'supplier_uuid' ) );

		if ( empty( $supplier_uuid ) ) {
			return Response_Builder::error(
				'invalid_data',
				'Supplier UUID is required.',
				400
			);
		}

		// Validate required data.
		if ( empty( $data['email'] ) ) {
			return Response_Builder::error(
				'invalid_data',
				'Email is required.',
				400
			);
		}

		if ( empty( $data['account_number'] ) || empty( $data['api_key'] ) ) {
			return Response_Builder::error(
				'invalid_data',
				'Account number and API key are required.',
				400
			);
		}

		$result = $this->handler->get_payment_profiles(
			$supplier_uuid,
			sanitize_email( $data['email'] ),
			sanitize_text_field( $data['account_number'] ),
			sanitize_text_field( $data['api_key'] )
		);

		if ( is_wp_error( $result ) ) {
			return Response_Builder::from_wp_error( $result );
		}

		return Response_Builder::success( $result );
	}

	/**
	 * Download debug logs for a supplier
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function download_debug_logs( $request ) {
		$supplier_uuid = sanitize_key( wp_unslash( $request->get_param( 'supplier_uuid' ) ) );

		$result = $this->handler->download_debug_logs( $supplier_uuid );

		if ( is_wp_error( $result ) ) {
			return Response_Builder::from_wp_error( $result );
		}

		return Response_Builder::success( $result );
	}

	/**
	 * Clear debug logs for a supplier
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function clear_debug_logs( $request ) {
		$supplier_uuid = sanitize_key( wp_unslash( $request->get_param( 'supplier_uuid' ) ) );

		$result = $this->handler->clear_debug_logs( $supplier_uuid );

		if ( is_wp_error( $result ) ) {
			return Response_Builder::from_wp_error( $result );
		}

		return Response_Builder::success( $result );
	}

	/**
	 * Get suppliers that have synced products (for deletion modal)
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function get_suppliers_with_products( $request ) {
		$result = $this->handler->get_suppliers_with_synced_products();

		if ( is_wp_error( $result ) ) {
			return Response_Builder::from_wp_error( $result );
		}

		return Response_Builder::success( $result );
	}

	/**
	 * Delete products for selected suppliers via bulk operation
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function bulk_delete_products( $request ) {
		$supplier_uuids = $request->get_param( 'supplier_uuids' );

		// Sanitize supplier UUIDs.
		$supplier_uuids = array_map( 'sanitize_text_field', $supplier_uuids );

		$result = $this->handler->bulk_delete_products_by_suppliers( $supplier_uuids );

		if ( is_wp_error( $result ) ) {
			return Response_Builder::from_wp_error( $result );
		}

		return Response_Builder::success( $result );
	}

	/**
	 * Download file via browser (triggers browser download)
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return void|WP_Error Exits on success or returns WP_Error on failure.
	 */
	public function download_file( $request ) {
		$file_path = $request->get_param( 'file_path' );
		$file_name = $request->get_param( 'file_name' );

		if ( empty( $file_path ) ) {
			return Response_Builder::error(
				'missing_file_path',
				'file_path parameter is required.',
				400
			);
		}

		$result = File_Save_Handler::handle_rest_api_file_download( $file_path, $file_name );

		if ( is_wp_error( $result ) ) {
			// Include additional debugging info in error response
			$error_data = $result->get_error_data();
			if ( isset( $error_data['file_path'] ) ) {
				$error_data['received_file_path'] = $file_path;
			}
			$result->add_data( $error_data );
			return Response_Builder::from_wp_error( $result );
		}

		return Response_Builder::error(
			'download_failed',
			'Failed to trigger download.',
			500
		);
	}

	/**
	 * Get list of available audit log CSV files for a supplier.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function get_audit_logs( $request ) {
		$supplier_uuid = sanitize_key( wp_unslash( $request->get_param( 'supplier_uuid' ) ) );
		$supplier      = Supplier_Model::get_by_uuid( $supplier_uuid );

		if ( empty( $supplier ) ) {
			return Response_Builder::error( 'supplier_not_found', 'Supplier not found.', 404 );
		}

		$supplier_id = (int) $supplier['id'];
		$files       = Supplier_Audit_Logger::get_audit_files( $supplier_id );

		return Response_Builder::success(
			array(
				'audit_mode'          => ! empty( $supplier['audit_mode'] ),
				'files'               => $files,
				'pending_sessions'    => Supplier_Audit_Logger::count_pending_session_files( $supplier_id ),
				'sync_in_progress'    => Product_Sync_Audit_Model::is_supplier_sync_in_progress( $supplier_id ),
			)
		);
	}

	/**
	 * Finalize orphaned session JSONL files into CSV (recovery when export did not run or failed).
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function finalize_audit_logs( $request ) {
		$supplier_uuid = sanitize_key( wp_unslash( $request->get_param( 'supplier_uuid' ) ) );

		$supplier = Supplier_Model::get_by_uuid( $supplier_uuid );
		if ( empty( $supplier ) ) {
			return Response_Builder::error( 'supplier_not_found', 'Supplier not found.', 404 );
		}

		$supplier_id = (int) $supplier['id'];
		$pending     = Supplier_Audit_Logger::count_pending_session_files( $supplier_id );
		// Recovery: allow finalizing orphaned JSONL when audit mode is off (session left after a failed export).
		if ( empty( $supplier['audit_mode'] ) && $pending < 1 ) {
			return Response_Builder::error( 'audit_disabled', 'Enable audit mode before generating a report, or wait until a session file is saved after a sync.', 400 );
		}

		if ( Product_Sync_Audit_Model::is_supplier_sync_in_progress( $supplier_id ) ) {
			return Response_Builder::error(
				'sync_in_progress',
				'Wait until the sync finishes, is paused, or is aborted before generating the report. Finalizing during an active sync can discard the session record.',
				400
			);
		}

		$ok = Supplier_Audit_Logger::finalize_pending_sessions( $supplier_id );

		if ( ! $ok ) {
			return Response_Builder::error(
				'finalize_failed',
				'Could not generate CSV. Ensure a session file exists and the audit directory is writable.',
				400
			);
		}

		$files = Supplier_Audit_Logger::get_audit_files( $supplier_id );

		$sid = $supplier_id;

		return Response_Builder::success(
			array(
				'message'            => 'Audit report generated.',
				'files'              => $files,
				'pending_sessions'   => Supplier_Audit_Logger::count_pending_session_files( $sid ),
				'sync_in_progress'   => Product_Sync_Audit_Model::is_supplier_sync_in_progress( $sid ),
			)
		);
	}

	/**
	 * Delete audit CSV files and unfinished session files for a supplier.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function clear_audit_logs( $request ) {
		$supplier_uuid = sanitize_key( wp_unslash( $request->get_param( 'supplier_uuid' ) ) );

		$result = $this->handler->clear_audit_logs( $supplier_uuid );

		if ( is_wp_error( $result ) ) {
			return Response_Builder::from_wp_error( $result );
		}

		return Response_Builder::success( $result );
	}

	/**
	 * Stream / download a specific audit log CSV.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return void|WP_Error
	 */
	public function download_audit_log( $request ) {
		$supplier_uuid = sanitize_key( wp_unslash( $request->get_param( 'supplier_uuid' ) ) );
		$file_index    = (int) $request->get_param( 'file_index' );

		$result = $this->handler->prepare_audit_log_download( $supplier_uuid, $file_index );
		if ( is_wp_error( $result ) ) {
			return Response_Builder::from_wp_error( $result );
		}

		$file_path = $result['file_path'];
		$filename  = $result['filename'];

		if ( headers_sent() ) {
			return Response_Builder::error( 'headers_sent', 'Unable to stream file: headers already sent.', 500 );
		}

		header( 'Content-Type: text/csv; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename="' . esc_attr( $filename ) . '"' );
		header( 'Content-Length: ' . filesize( $file_path ) );
		header( 'Cache-Control: no-cache, no-store, must-revalidate' );
		header( 'Pragma: no-cache' );
		header( 'Expires: 0' );
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Raw CSV bytes via readfile().
		readfile( $file_path );
		exit;
	}
}
