<?php
/**
 * Authorization Model
 *
 * @category   WordPress_Plugin
 * @package    Common
 * @subpackage Models
 * @author     miniOrange <info@miniorange.com>
 * @license    MIT/Expat
 * @link       https://plugins.miniorange.com/woocommerce-api-product-sync-with-woocommerce-rest-apis
 */

namespace MOWCPS\Common\Models;

use MOWCPS\Common\Interfaces\Model_Interface;
use MOWCPS\Common\Constants\Constants;
use WP_Error;
use MOWCPS\Common\Utils\Model_Utils;

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

/**
 * Class Authorization_Model
 *
 * Handles authorization data operations
 */
class Authorization_Model implements Model_Interface {
	/**
	 * Database table name
	 *
	 * @var string
	 */
	private static $table_name = Model_Utils::TABLE_AUTHORIZATION;

	/**
	 * Valid auth types
	 *
	 * @var array
	 */
	private static $valid_auth_types = array(
		Constants::AUTH_TYPE_NO_AUTH,
		Constants::AUTH_TYPE_BASIC,
		Constants::AUTH_TYPE_BEARER,
		Constants::AUTH_TYPE_API_KEY,
		Constants::AUTH_TYPE_OAUTH2,
		Constants::AUTH_TYPE_CUSTOM,
	);

	/**
	 * Get all authorization records
	 *
	 * @param array $args Query parameters (not used).
	 * @return array List of authorization records
	 */
	public static function get_all( $args = array() ) {
		global $wpdb;
		$table_name = Model_Utils::get_table_name( self::$table_name );
		$results    = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$table_name}`" ), ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom query.

		// Decode JSON auth_settings for each result.
		// Decode JSON fields.
		$results = Model_Utils::decode_json_fields( $results, array( 'auth_settings' ) );

		return $results ? $results : array();
	}

	/**
	 * Get authorization by UUID (not applicable for this model)
	 *
	 * @param string $uuid The UUID.
	 * @return array|null
	 */
	public static function get_by_uuid( $uuid ) {
		// Authorization doesn't have UUID, use get_by_supplier_id instead.
		return null;
	}

	/**
	 * Get authorization by supplier ID
	 *
	 * @param int $supplier_id The supplier ID.
	 * @return array|null Authorization data or null if not found
	 */
	public static function get_by_supplier_id( $supplier_id ) {
		global $wpdb;

		$table_name = Model_Utils::get_table_name( self::$table_name );

		$authorization = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM `{$table_name}` WHERE supplier_id = %d",
				$supplier_id
			),
			ARRAY_A
		);

		// Decode JSON fields.
		$authorization = Model_Utils::decode_json_fields( $authorization, array( 'auth_settings' ) );

		return $authorization;
	}

	/**
	 * Create new authorization
	 *
	 * @param array $data The authorization data.
	 * @return array|WP_Error Created authorization data or error
	 */
	public static function create( $data ) {
		global $wpdb;

		// Validate required fields.
		if ( empty( $data['supplier_id'] ) ) {
			return new WP_Error(
				Constants::ERROR_MISSING_REQUIRED_FIELD,
				sprintf( Constants::MSG_MISSING_REQUIRED_FIELD, 'supplier_id' ),
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Validate auth_type.
		$auth_type = $data['auth_type'] ?? Constants::AUTH_TYPE_NO_AUTH;
		if ( ! in_array( $auth_type, self::$valid_auth_types, true ) ) {
			return new WP_Error(
				Constants::ERROR_INVALID_AUTH_TYPE,
				Constants::MSG_INVALID_AUTH_TYPE,
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		// Check if authorization already exists for this supplier.
		$existing = self::get_by_supplier_id( $data['supplier_id'] );
		if ( $existing ) {
			return new WP_Error(
				Constants::ERROR_DUPLICATE_ENTRY,
				Constants::MSG_DUPLICATE_ENTRY,
				array( 'status' => Constants::HTTP_CONFLICT )
			);
		}

		// For no-auth, always set auth_settings to null regardless of input.
		$auth_settings = null;
		if ( Constants::AUTH_TYPE_NO_AUTH !== $auth_type && isset( $data['auth_settings'] ) && is_array( $data['auth_settings'] ) ) {
			$auth_settings = wp_json_encode( $data['auth_settings'] );
		}

		$insert_data = array(
			'supplier_id'   => intval( $data['supplier_id'] ),
			'auth_type'     => $auth_type,
			'auth_settings' => $auth_settings,
		);

		$table_name = Model_Utils::get_table_name( self::$table_name );

		$result = $wpdb->insert(
			$table_name,
			$insert_data,
			array( '%d', '%s', '%s' )
		);

		if ( false === $result ) {
			return new WP_Error(
				Constants::ERROR_DB_ERROR,
				sprintf( Constants::MSG_DB_ERROR, $wpdb->last_error ),
				array( 'status' => Constants::HTTP_INTERNAL_SERVER_ERROR )
			);
		}

		return self::get_by_supplier_id( $data['supplier_id'] );
	}

	/**
	 * Update authorization (not applicable with UUID, use update_by_supplier_id)
	 *
	 * @param string $uuid The UUID.
	 * @param array  $data The data.
	 * @return array|WP_Error
	 */
	public static function update( $uuid, $data ) {
		return new WP_Error(
			Constants::ERROR_NOT_SUPPORTED,
			sprintf( Constants::MSG_NOT_SUPPORTED, 'Use update_by_supplier_id method instead.' ),
			array( 'status' => Constants::HTTP_BAD_REQUEST )
		);
	}

	/**
	 * Update authorization by supplier ID
	 *
	 * @param int   $supplier_id The supplier ID.
	 * @param array $data The authorization data.
	 * @return array|WP_Error Updated authorization data or error
	 */
	public static function update_by_supplier_id( $supplier_id, $data ) {
		global $wpdb;

		$existing = self::get_by_supplier_id( $supplier_id );
		if ( ! $existing ) {
			return new WP_Error(
				Constants::ERROR_RECORD_NOT_FOUND,
				Constants::MSG_RECORD_NOT_FOUND,
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		// Validate auth_type if provided.
		$update_data = array();
		if ( isset( $data['auth_type'] ) ) {
			$auth_type = $data['auth_type'];
			if ( ! in_array( $auth_type, self::$valid_auth_types, true ) ) {
				return new WP_Error(
					Constants::ERROR_INVALID_AUTH_TYPE,
					Constants::MSG_INVALID_AUTH_TYPE,
					array( 'status' => Constants::HTTP_BAD_REQUEST )
				);
			}
			$update_data['auth_type'] = $auth_type;

			// If changing to no-auth, force auth_settings to null.
			if ( Constants::AUTH_TYPE_NO_AUTH === $auth_type ) {
				$update_data['auth_settings'] = null;
				// Remove auth_settings from data to prevent processing below.
				unset( $data['auth_settings'] );
			}
		}

		// Handle auth_settings only if not changing to no-auth.
		if ( isset( $data['auth_settings'] ) ) {
			$current_auth_type = $update_data['auth_type'] ?? $existing['auth_type'];
			if ( Constants::AUTH_TYPE_NO_AUTH === $current_auth_type ) {
				$update_data['auth_settings'] = null;
			} elseif ( is_array( $data['auth_settings'] ) ) {
				$update_data['auth_settings'] = wp_json_encode( $data['auth_settings'] );
			} else {
				$update_data['auth_settings'] = null;
			}
		}

		if ( empty( $update_data ) ) {
			return new WP_Error(
				Constants::ERROR_NO_DATA,
				Constants::MSG_NO_DATA,
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}

		$table_name = Model_Utils::get_table_name( self::$table_name );

		$result = $wpdb->update(
			$table_name,
			$update_data,
			array( 'supplier_id' => $supplier_id ),
			array( '%s', '%s' ),
			array( '%d' )
		);

		if ( false === $result ) {
			return new WP_Error(
				Constants::ERROR_DB_ERROR,
				sprintf( Constants::MSG_DB_ERROR, $wpdb->last_error ),
				array( 'status' => Constants::HTTP_INTERNAL_SERVER_ERROR )
			);
		}

		// Delete cached authentication token since settings have changed.
		self::delete_cached_token( $supplier_id );

		return self::get_by_supplier_id( $supplier_id );
	}

	/**
	 * Delete authorization (not applicable with UUID, use delete_by_supplier_id)
	 *
	 * @param string $uuid The UUID.
	 * @return bool|WP_Error
	 */
	public static function delete( $uuid ) {
		return new WP_Error(
			Constants::ERROR_NOT_SUPPORTED,
			sprintf( Constants::MSG_NOT_SUPPORTED, 'Use delete_by_supplier_id method instead.' ),
			array( 'status' => Constants::HTTP_BAD_REQUEST )
		);
	}

	/**
	 * Delete authorization by supplier ID
	 *
	 * @param int $supplier_id The supplier ID.
	 * @return bool|WP_Error True on success, WP_Error on failure
	 */
	public static function delete_by_supplier_id( $supplier_id ) {
		global $wpdb;

		$existing = self::get_by_supplier_id( $supplier_id );
		if ( ! $existing ) {
			return new WP_Error(
				Constants::ERROR_RECORD_NOT_FOUND,
				Constants::MSG_RECORD_NOT_FOUND,
				array( 'status' => Constants::HTTP_NOT_FOUND )
			);
		}

		$table_name = Model_Utils::get_table_name( self::$table_name );

		$result = $wpdb->delete(
			$table_name,
			array( 'supplier_id' => $supplier_id ),
			array( '%d' )
		);

		if ( false === $result ) {
			return new WP_Error(
				Constants::ERROR_DB_ERROR,
				sprintf( Constants::MSG_DB_ERROR, $wpdb->last_error ),
				array( 'status' => Constants::HTTP_INTERNAL_SERVER_ERROR )
			);
		}

		return true;
	}

	/**
	 * Get valid auth types
	 *
	 * @return array Valid auth types
	 */
	public static function get_valid_auth_types() {
		return self::$valid_auth_types;
	}

	/**
	 * Delete cached authentication token for a supplier
	 *
	 * @param int $supplier_id Supplier ID.
	 * @return bool True if token was deleted, false if not found.
	 */
	public static function delete_cached_token( $supplier_id ) {
		$transient_key = 'mowcps_auth_token_' . $supplier_id;
		return delete_transient( $transient_key );
	}
}
