<?php
/**
 * Supplier Handler
 *
 * @category   WordPress_Plugin
 * @package    Common
 * @subpackage Handlers\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\Handlers\Rest_API;

use WP_Error;
use MOWCPS\Common\Models\Supplier_Model;
use MOWCPS\Common\DTO\Supplier_Request;
use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Services\Logging\Supplier_Logger;
use MOWCPS\Common\Services\Auditing\Supplier_Audit_Logger;
use MOWCPS\Common\Utils\Model_Utils;
use MOWCPS\Common\Services\Import_Supplier\Import_Supplier as Import_Supplier_Services;
use MOWCPS\Common\Constants\Plugin_Filters;
use MOWCPS\Common\Services\Cache\Cache_Service;
use MOWCPS\Common\Suppliers\Sns_Activewear;
use MOWCPS\Common\Suppliers\Turn14;

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

/**
 * Class Supplier_Handler
 *
 * Handles supplier REST API operations
 */
class Supplier_Handler {

	const CACHE_KEY_LIST = 'mowcps_suppliers_list_v2';

	/**
	 * Logger instance
	 *
	 * @var Supplier_Logger
	 */
	private $logger;

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

	/**
	 * Get all suppliers
	 *
	 * @param array $params Query parameters.
	 * @return array|WP_Error
	 */
	public function get_all( $params = array() ) {
		// Process column selection if provided.
		if ( isset( $params['columns'] ) ) {
			$validated_columns = Supplier_Request::validate_columns( $params['columns'] );
			if ( is_wp_error( $validated_columns ) ) {
				return $validated_columns;
			}
			$params['columns'] = $validated_columns;
		}

		return Cache_Service::remember( self::CACHE_KEY_LIST, Cache_Service::DEFAULT_EXPIRATION, function () use ( $params ) {
			$suppliers = Supplier_Model::get_all( $params );
			return Model_Utils::sanitize_for_api_response( $suppliers );
		} );
	}

	/**
	 * Get supplier by UUID
	 *
	 * @param string $uuid Supplier UUID.
	 * @return array|WP_Error
	 */
	public function get_by_uuid( $uuid ) {
		// Validate UUID parameter using DTO.
		$validation = Supplier_Request::validate_uuid( $uuid, 'supplier_uuid' );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		$supplier = Supplier_Model::get_by_uuid( $uuid );

		if ( ! $supplier ) {
			return new WP_Error(
				Constants::ERROR_SUPPLIER_NOT_FOUND,
				Constants::MSG_SUPPLIER_NOT_FOUND,
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		// Remove ID fields from API response.
		return Model_Utils::sanitize_for_api_response( $supplier );
	}

	/**
	 * Get supplier by ID
	 *
	 * @param int $id Supplier ID.
	 * @return array|WP_Error
	 */
	public function get_by_id( $id ) {
		$supplier = Supplier_Model::get_by_id( $id );

		if ( ! $supplier ) {
			return new WP_Error(
				Constants::ERROR_SUPPLIER_NOT_FOUND,
				Constants::MSG_SUPPLIER_NOT_FOUND,
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		return $supplier;
	}

	/**
	 * Create supplier
	 *
	 * @param array $data Supplier data.
	 * @return array|WP_Error
	 */
	public function create( $data ) {
		// Transform and validate data using DTO.
		$supplier_request = Supplier_Request::from_request_parameters( $data );
		if ( is_wp_error( $supplier_request ) ) {
			return $supplier_request;
		}

		$validated_data = $supplier_request->to_array();
		$result         = Supplier_Model::create( $validated_data );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		Cache_Service::forget( self::CACHE_KEY_LIST );

		// Remove ID fields from API response.
		return Model_Utils::sanitize_for_api_response( $result );
	}

	/**
	 * Update supplier
	 *
	 * @param string $uuid Supplier UUID.
	 * @param array  $data Supplier data.
	 * @return array|WP_Error
	 */
	public function update( $uuid, $data ) {
		// Validate UUID parameter using DTO.
		$validation = Supplier_Request::validate_uuid( $uuid, 'supplier_uuid' );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		// Transform and validate data using DTO for updates.
		$supplier_request = Supplier_Request::from_update_parameters( $data );
		if ( is_wp_error( $supplier_request ) ) {
			return $supplier_request;
		}

		$validated_data = $supplier_request->to_array();
		$result         = Supplier_Model::update( $uuid, $validated_data );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		Cache_Service::forget( self::CACHE_KEY_LIST );
		self::forget_supplier_brands_cache( $validated_data );

		// Remove ID fields from API response.
		return Model_Utils::sanitize_for_api_response( $result );
	}

	/**
	 * Delete supplier
	 *
	 * @param string $uuid Supplier UUID.
	 * @return bool|WP_Error
	 */
	public function delete( $uuid ) {
		// Validate UUID parameter using DTO.
		$validation = Supplier_Request::validate_uuid( $uuid, 'supplier_uuid' );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		$supplier_before = Supplier_Model::get_by_uuid( $uuid );
		$result          = Supplier_Model::delete( $uuid );

		if ( ! is_wp_error( $result ) ) {
			Cache_Service::forget( self::CACHE_KEY_LIST );
			self::forget_supplier_brands_cache( $supplier_before );
		}

		return $result;
	}

	/**
	 * Clear SNS/Turn14 brands cache for a supplier (by country for SNS; single key for Turn14). No-op if supplier is not SNS or Turn14.
	 *
	 * @param array|null $supplier Supplier record with app_type and details.
	 * @return void
	 */
	private static function forget_supplier_brands_cache( $supplier ) {
		if ( empty( $supplier ) || ! is_array( $supplier ) ) {
			return;
		}
		$app_type = $supplier['app_type'] ?? '';
		$details  = isset( $supplier['details'] ) ? ( is_string( $supplier['details'] ) ? json_decode( $supplier['details'], true ) : $supplier['details'] ) : array();
		if ( Constants::SUPPLIER_APP_TYPE_SNS_ACTIVEWEAR === $app_type && ! empty( $details['country'] ) ) {
			Cache_Service::forget( Sns_Activewear::CACHE_KEY_PREFIX_CATEGORIES_BRANDS . $details['country'] );
		}
		if ( Constants::SUPPLIER_APP_TYPE_TURN14 === $app_type ) {
			Cache_Service::forget( Turn14::CACHE_KEY_BRANDS );
		}
	}

	/**
	 * Test supplier connection configuration
	 *
	 * @param array $supplier_data Supplier data containing app_type and details.
	 * @return array|WP_Error Test result or error.
	 */
	public function test_supplier( $supplier_data ) {
		// Validate supplier data.
		if ( empty( $supplier_data['app_type'] ) ) {
			return new WP_Error(
				Constants::ERROR_MISSING_REQUIRED_FIELD,
				'Supplier app type is required for testing.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		if ( empty( $supplier_data['details'] ) ) {
			return new WP_Error(
				Constants::ERROR_MISSING_REQUIRED_FIELD,
				'Supplier details are required for testing.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Validate connection data using DTO with test-specific validation.
		$supplier_request = Supplier_Request::from_test_parameters( $supplier_data );
		if ( is_wp_error( $supplier_request ) ) {
			return $supplier_request;
		}

		$namespace        = false !== strpos( Constants::MOWCPS_PLAN_NAME, 'standard' ) ? 'Common' : MOWCPS_PLAN_NAMESPACE;
		$supplier_factory = 'MOWCPS\\' . $namespace . '\\Factories\\Supplier_App_Factory';

		// Create supplier app instance using factory.
		$supplier_app = $supplier_factory::create_supplier_app( $supplier_data['app_type'] );
		if ( is_wp_error( $supplier_app ) ) {
			return $supplier_app;
		}

		/**
		 * Hook for altering supplier payload before testing the connection.
		 *
		 * @param array $supplier_data Supplier data.
		 * @return array Altered supplier data.
		 */
		if ( has_filter( Plugin_Filters::FILTER_ALTER_SUPPLIER_PAYLOAD ) ) {
			$returned_data = apply_filters( Plugin_Filters::FILTER_ALTER_SUPPLIER_PAYLOAD,
				array(
					'supplier_data' => $supplier_data,
				)
			);

			$supplier_data = $returned_data['supplier_data'];
		}

		// Test connection using the supplier app.
		$result = $supplier_app->test_connection( $supplier_data['app_type'], $supplier_data['details'] );

		return $result;
	}

	/**
	 * Get SNS Activewear payment profiles
	 *
	 * @param string $supplier_uuid Supplier UUID to get country from supplier details.
	 * @param string $email Email address.
	 * @param string $account_number Account number.
	 * @param string $api_key API key.
	 * @return array|WP_Error Payment profiles or error.
	 */
	public function get_payment_profiles( $supplier_uuid, $email, $account_number, $api_key ) {
		// Create Basic Auth credentials.
		$credentials = base64_encode( $account_number . ':' . $api_key );

		// Get supplier to determine country code for API URL.
		$supplier = Supplier_Model::get_by_uuid( $supplier_uuid );
		if ( ! $supplier ) {
			return new WP_Error(
				Constants::ERROR_SUPPLIER_NOT_FOUND,
				Constants::MSG_SUPPLIER_NOT_FOUND,
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		// Get country from supplier details - exact key path: details['country'].
		$details = is_string( $supplier['details'] ) ? json_decode( $supplier['details'], true ) : $supplier['details'];
		$country = isset( $details['country'] ) ? strtoupper( $details['country'] ) : 'US';

		// Determine country code for API URL (CA uses '-ca', US uses empty string).
		$country_code = ( Constants::COUNTRY_CA === $country ) ? '-ca' : '';

		// Make API call to SNS Activewear.
		$url = 'https://api' . $country_code . '.ssactivewear.com/v2/paymentprofiles/?email=' . urlencode( $email );

		$response = wp_remote_get(
			$url,
			array(
				'headers' => array(
					'Content-Type'  => 'application/json',
					'Authorization' => 'Basic ' . $credentials,
				),
				'timeout' => 30,
			)
		);

		// Check for errors.
		if ( is_wp_error( $response ) ) {
			return new WP_Error(
				'api_request_failed',
				$response->get_error_message(),
				array( 'status' => Constants::HTTP_INTERNAL_SERVER_ERROR )
			);
		}

		$response_code = wp_remote_retrieve_response_code( $response );
		$response_body = wp_remote_retrieve_body( $response );

		if ( $response_code !== 200 ) {
			$error_data = json_decode( $response_body, true );
			$error_msg  = isset( $error_data['error']['message'] ) ? $error_data['error']['message'] : 'Failed to fetch payment profiles';

			return new WP_Error(
				'api_error',
				$error_msg,
				array( 'status' => $response_code )
			);
		}

		$data = json_decode( $response_body, true );

		// Return the data as-is, let frontend handle formatting.
		return $data;
	}

	/**
	 * Download debug logs for a supplier
	 *
	 * @param string $uuid Supplier UUID.
	 * @return array|WP_Error
	 */
	public function download_debug_logs( $uuid ) {
		// Validate UUID parameter using DTO.
		$validation = Supplier_Request::validate_uuid( $uuid, 'supplier_uuid' );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		// Get supplier to validate UUID exists.
		$supplier = Supplier_Model::get_by_uuid( $uuid );
		if ( ! $supplier ) {
			return new WP_Error(
				Constants::ERROR_SUPPLIER_NOT_FOUND,
				Constants::MSG_SUPPLIER_NOT_FOUND,
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		$supplier_name = $supplier['name'];

		// Check if logging is enabled.
		if ( ! ( (bool) $supplier['debug_mode'] && (bool) $supplier['is_active'] ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_REQUEST,
				'Debug logging is not enabled for this supplier.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Use logger service to get file content.
		$result = $this->logger->download_supplier_log_file( $supplier_name );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		// Add supplier information to the result.
		$result['supplier'] = array(
			'uuid' => $uuid,
			'name' => $supplier_name,
		);

		return $result;
	}

	/**
	 * Clear debug logs for a supplier
	 *
	 * @param string $uuid Supplier UUID.
	 * @return array|WP_Error
	 */
	public function clear_debug_logs( $uuid ) {
		// Validate UUID parameter using DTO.
		$validation = Supplier_Request::validate_uuid( $uuid, 'supplier_uuid' );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		// Get supplier to validate UUID exists.
		$supplier = Supplier_Model::get_by_uuid( $uuid );
		if ( ! $supplier ) {
			return new WP_Error(
				Constants::ERROR_SUPPLIER_NOT_FOUND,
				Constants::MSG_SUPPLIER_NOT_FOUND,
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		$supplier_name = $supplier['name'];

		// Use logger service to clear logs.
		$result = $this->logger->delete_supplier_logs( $supplier_name );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		// Add supplier information to the result.
		$result['supplier'] = array(
			'uuid' => $uuid,
			'name' => $supplier_name,
		);

		return $result;
	}

	/**
	 * Clear audit CSV and session files for a supplier.
	 *
	 * @param string $uuid Supplier UUID.
	 * @return array|WP_Error
	 */
	public function clear_audit_logs( $uuid ) {
		$validation = Supplier_Request::validate_uuid( $uuid, 'supplier_uuid' );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		$supplier = Supplier_Model::get_by_uuid( $uuid );
		if ( ! $supplier ) {
			return new WP_Error(
				Constants::ERROR_SUPPLIER_NOT_FOUND,
				Constants::MSG_SUPPLIER_NOT_FOUND,
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		$result = Supplier_Audit_Logger::clear_all_audit_files( (int) $supplier['id'] );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		$result['supplier'] = array(
			'uuid' => $uuid,
			'name' => $supplier['name'],
		);

		return $result;
	}

	/**
	 * Resolve an audit CSV path for download (supplier + file index validation).
	 *
	 * @param string $uuid       Supplier UUID.
	 * @param int    $file_index Audit file index from listing endpoint.
	 * @return array|WP_Error {
	 *     @type string $file_path Absolute path to the CSV file.
	 *     @type string $filename  Basename for Content-Disposition.
	 * }
	 */
	public function prepare_audit_log_download( $uuid, $file_index ) {
		$validation = Supplier_Request::validate_uuid( $uuid, 'supplier_uuid' );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		$supplier = Supplier_Model::get_by_uuid( $uuid );
		if ( ! $supplier ) {
			return new WP_Error(
				'supplier_not_found',
				'Supplier not found.',
				array( 'status' => 404 )
			);
		}

		$file_path = Supplier_Audit_Logger::get_audit_file_path( (int) $supplier['id'], (int) $file_index );
		if ( empty( $file_path ) || ! file_exists( $file_path ) ) {
			return new WP_Error(
				'audit_file_not_found',
				'Audit log file not found.',
				array( 'status' => 404 )
			);
		}

		return array(
			'file_path' => $file_path,
			'filename'  => basename( $file_path ),
		);
	}

	/**
	 * Delete products for selected suppliers via bulk operation
	 *
	 * @param array $supplier_ids Array of supplier IDs (numeric).
	 * @return array|WP_Error
	 */
	public function bulk_delete_products_by_suppliers( $supplier_ids ) {
		// Validate input.
		if ( empty( $supplier_ids ) || ! is_array( $supplier_ids ) ) {
			return new WP_Error(
				Constants::ERROR_MISSING_REQUIRED_FIELD,
				'Supplier IDs are required.',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Use the supplier ID deletion method from Model_Utils.
		$result = Model_Utils::delete_all_products_by_mixed_identifiers( $supplier_ids );

		if ( is_wp_error( $result ) ) {
			return $result;
		}

		return $result;
	}

	/**
	 * Get suppliers that have synced products
	 *
	 * @return array List of suppliers that have products with mowcps_connection_name_product_created meta.
	 */
	public function get_suppliers_with_synced_products() {
		return Supplier_Model::get_suppliers_with_synced_products();
	}

	public function create_bulk_suppliers( $data, $overwrite_if_exist ) {
		$export_supplier_service = new Import_Supplier_Services();
		$result                  = $export_supplier_service->import_supplier( $data, $overwrite_if_exist );

		Cache_Service::forget( self::CACHE_KEY_LIST );

		return $result;
	}
}
