<?php

namespace WeeConnectPay;

/**
 * Environment registry for WeeConnectPay.
 *
 * Defines the four standard environments (local, sandbox, staging, production)
 * with their API URLs, Clover app UUIDs, SDK URLs, and verification URIs.
 * Manages the currently selected environment via WordPress options.
 *
 * @since 4.1.0
 */
class Environment {

	const DB_KEY = 'weeconnectpay_environment';
	const DEFAULT_ENVIRONMENT = 'production';

	/**
	 * Registry of all known environments.
	 * App UUIDs are WooCommerce-specific.
	 */
	private const ENVIRONMENTS = array(
		'local' => array(
			'label'            => 'Local',
			'api_base_url'     => 'http://weeconnect-api.test',
			'app_uuid'         => 'ZAVE6HARYPJ6P',
			'verification_uri' => 'https://login.staging.weeconnectpay.com/connect',
			'clover_sdk_url'   => 'https://checkout.sandbox.dev.clover.com/sdk.js',
			'clover_3ds_sdk_url' => 'https://checkout.dev1.dev.clover.com/clover3DS/clover3DS-sdk.js',
		),
		'sandbox' => array(
			'label'            => 'Sandbox',
			'api_base_url'     => 'https://apidev.weeconnectpay.com',
			'app_uuid'         => '50TGE8JTBF268',
			'verification_uri' => 'https://login.sandbox.weeconnectpay.com/connect',
			'clover_sdk_url'   => 'https://checkout.sandbox.dev.clover.com/sdk.js',
			'clover_3ds_sdk_url' => 'https://checkout.dev1.dev.clover.com/clover3DS/clover3DS-sdk.js',
		),
		'staging' => array(
			'label'            => 'Staging',
			'api_base_url'     => 'https://apidev.weeconnectpay.com',
			'app_uuid'         => 'HH7W7QN8VQ858',
			'verification_uri' => 'https://login.staging.weeconnectpay.com/connect',
			'clover_sdk_url'   => 'https://checkout.sandbox.dev.clover.com/sdk.js',
			'clover_3ds_sdk_url' => 'https://checkout.dev1.dev.clover.com/clover3DS/clover3DS-sdk.js',
		),
		'production' => array(
			'label'            => 'Production',
			'api_base_url'     => 'https://api.weeconnectpay.com',
			'app_uuid'         => 'H898KZE13VBXY',
			'verification_uri' => 'https://login.weeconnectpay.com/connect',
			'clover_sdk_url'   => 'https://checkout.clover.com/sdk.js',
			'clover_3ds_sdk_url' => 'https://checkout.clover.com/clover3DS/clover3DS-sdk.js',
		),
	);

	/**
	 * Get the currently selected environment key.
	 *
	 * @return string One of: local, sandbox, staging, production
	 */
	public static function getCurrentKey(): string {
		$key = get_option( self::DB_KEY, self::DEFAULT_ENVIRONMENT );

		if ( ! isset( self::ENVIRONMENTS[ $key ] ) ) {
			return self::DEFAULT_ENVIRONMENT;
		}

		return $key;
	}

	/**
	 * Set the current environment.
	 *
	 * @param string $key One of: local, sandbox, staging, production
	 * @return bool True if valid and saved, false if invalid key.
	 */
	public static function setCurrentKey( string $key ): bool {
		if ( ! isset( self::ENVIRONMENTS[ $key ] ) ) {
			return false;
		}

		update_option( self::DB_KEY, $key );
		return true;
	}

	/**
	 * Get the config array for a specific environment.
	 *
	 * @param string $key
	 * @return array
	 */
	public static function get( string $key ): array {
		if ( isset( self::ENVIRONMENTS[ $key ] ) ) {
			return self::ENVIRONMENTS[ $key ];
		}

		return self::ENVIRONMENTS[ self::DEFAULT_ENVIRONMENT ];
	}

	/**
	 * Get the config array for the current environment.
	 *
	 * @return array
	 */
	public static function getCurrent(): array {
		return self::get( self::getCurrentKey() );
	}

	/**
	 * Get the API base URL for the current environment.
	 * Respects GitPod override when applicable.
	 *
	 * @return string
	 */
	public static function getApiBaseUrl(): string {
		if ( getenv( 'GITPOD_WORKSPACE_URL' ) ) {
			if ( defined( 'GITPOD_WCP_BACKEND_WORKSPACE_URL' ) ) {
				return GITPOD_WCP_BACKEND_WORKSPACE_URL;
			}
			return 'GITPOD_URL_NOT_SET';
		}

		$config = self::getCurrent();
		return $config['api_base_url'];
	}

	/**
	 * Get the Clover app UUID for the current environment.
	 *
	 * @return string
	 */
	public static function getAppUuid(): string {
		$config = self::getCurrent();
		return $config['app_uuid'];
	}

	/**
	 * Get the Clover SDK URL for the current environment.
	 *
	 * @return string
	 */
	public static function getCloverSdkUrl(): string {
		$config = self::getCurrent();
		return $config['clover_sdk_url'];
	}

	/**
	 * Get the Clover 3-D Secure SDK URL for the current environment.
	 *
	 * Production lives on the same host as the payments SDK, but non-prod 3DS
	 * is on a separate host (checkout.dev1.dev.clover.com) — distinct from
	 * the payments sandbox (checkout.sandbox.dev.clover.com).
	 *
	 * @return string
	 */
	public static function getClover3DSSdkUrl(): string {
		$config = self::getCurrent();
		return $config['clover_3ds_sdk_url'];
	}

	/**
	 * Get the verification URI for the current environment.
	 *
	 * @return string
	 */
	public static function getVerificationUri(): string {
		$config = self::getCurrent();
		return $config['verification_uri'];
	}

	/**
	 * Build an environment-suffixed key from a base suffix.
	 * e.g. configKey('jwt') => 'jwt_production'
	 *
	 * @param string $baseSuffix The base key suffix (e.g. 'jwt', 'oauth_client_id')
	 * @return string
	 */
	public static function configKey( string $baseSuffix ): string {
		return $baseSuffix . '_' . self::getCurrentKey();
	}

	/**
	 * Build an environment-suffixed key for a specific environment.
	 * e.g. configKeyFor('jwt', 'sandbox') => 'jwt_sandbox'
	 *
	 * @param string $baseSuffix
	 * @param string $envKey
	 * @return string
	 */
	public static function configKeyFor( string $baseSuffix, string $envKey ): string {
		return $baseSuffix . '_' . $envKey;
	}

	/**
	 * Check whether the current environment is production.
	 *
	 * @return bool
	 */
	public static function isProduction(): bool {
		return self::getCurrentKey() === 'production';
	}

	/**
	 * Get all environment keys.
	 *
	 * @return string[]
	 */
	public static function all(): array {
		return array_keys( self::ENVIRONMENTS );
	}

	/**
	 * Get the full registry.
	 *
	 * @return array
	 */
	public static function getAll(): array {
		return self::ENVIRONMENTS;
	}

	/**
	 * Get visible environments for the UI.
	 * Shows 'local' only when the site is on a local-development host
	 * (.test domain, localhost, or 127.0.0.1) or already set to local.
	 * Otherwise excludes 'local'.
	 *
	 * `isProduction` lets the UI warn, non-dismissably, that non-production
	 * environments do not process real payments. `isConnected` flags which
	 * environments already hold credentials.
	 *
	 * @return array Array of ['key' => string, 'label' => string, 'isProduction' => bool, 'isConnected' => bool]
	 */
	public static function getVisibleEnvironments(): array {
		$host      = wp_parse_url( site_url(), PHP_URL_HOST );
		$isDevHost = $host && ( preg_match( '/\.test$/', $host ) || $host === 'localhost' || $host === '127.0.0.1' );
		$showLocal = $isDevHost || self::getCurrentKey() === 'local';
		$result    = array();

		foreach ( self::ENVIRONMENTS as $key => $config ) {
			if ( $key === 'local' && ! $showLocal ) {
				continue;
			}

			$result[] = array(
				'key'          => $key,
				'label'        => $config['label'],
				'isProduction' => $key === self::DEFAULT_ENVIRONMENT,
				'isConnected'  => self::isConnected( $key ),
			);
		}

		return $result;
	}

	/**
	 * Whether an environment holds working credentials — the signal behind the env
	 * switcher's "connected" dot.
	 *
	 * A token row alone is not enough: after a Clover-side revocation the row lingers
	 * while the integration is dead, which is exactly why the dot used to stay green on
	 * a disconnected environment. So once a token exists we defer to the authoritative
	 * cached health verdict — the same signal the settings login-screen gate uses
	 * ({@see Integrations\IntegrationHealth::isDisconnectedForEnv}) — when the health
	 * module is loaded (it is at settings render, where this runs). If it isn't, fall
	 * back to token presence rather than risk a fatal in an early/partial context.
	 *
	 * @param string $envKey
	 * @return bool
	 */
	public static function isConnected( string $envKey ): bool {
		$jwtKey = 'weeconnectpay_jwt_' . $envKey;
		if ( ! get_option( $jwtKey, false ) ) {
			return false;
		}

		if ( class_exists( '\WeeConnectPay\Integrations\IntegrationHealth' ) ) {
			return ! \WeeConnectPay\Integrations\IntegrationHealth::isDisconnectedForEnv( $envKey );
		}

		return true;
	}

	/**
	 * Map a Clover app UUID to an environment key.
	 * Used during migration from unsuffixed to per-environment keys.
	 *
	 * @param string $uuid
	 * @return string|null Environment key or null if not recognized
	 */
	public static function envKeyFromAppUuid( string $uuid ): ?string {
		foreach ( self::ENVIRONMENTS as $key => $config ) {
			if ( $config['app_uuid'] === $uuid ) {
				return $key;
			}
		}

		return null;
	}
}
