<?php

namespace WPML\UrlHandling;

use WPML\Element\API\Languages;
use WPML\FP\Obj;
use WPML\FP\Relation;
use WPML\FP\Str;

class WPLoginUrlConverter implements \IWPML_Action {
	const PRIORITY_AFTER_URL_FILTERS = 100;
	const SETTINGS_KEY = 'wpml_login_page_translation';

	private $rewrite_rule_not_found;

	/** @var \WPML_URL_Converter $url_converter */
	private $url_converter;

	/** @var \SitePress $sitepress */
	private $sitepress;

	/**
	 * @param \WPML_URL_Converter $url_converter
	 * @param \SitePress $sitepress
	 */
	public function __construct( $sitepress, $url_converter ) {
		$this->rewrite_rule_not_found = false;
		$this->url_converter          = $url_converter;
		$this->sitepress              = $sitepress;
	}

	public function add_hooks() {

		add_filter( 'site_url', [ $this, 'site_url' ], self::PRIORITY_AFTER_URL_FILTERS, 3 );
		add_filter( 'login_url', [ $this, 'convert_url' ] );
		add_filter( 'register_url', [ $this, 'convert_url' ] );
		add_filter( 'lostpassword_url', [ $this, 'convert_url' ] );
		add_filter( 'request', [ $this, 'on_request' ] );
		add_filter( 'wpml_get_language_from_url', [
			$this,
			'wpml_login_page_language_from_url'
		], self::PRIORITY_AFTER_URL_FILTERS, 2 );
		add_filter( 'registration_redirect', [ $this, 'filter_redirect_with_lang' ] );
		add_filter( 'lostpassword_redirect', [ $this, 'filter_redirect_with_lang' ] );

		add_action( 'generate_rewrite_rules', [ $this, 'generate_rewrite_rules' ] );
		add_action( 'login_init', [ $this, 'redirect_to_login_url_with_lang' ] );

		if ( is_multisite() ) {
			add_filter( 'network_site_url', [ $this, 'site_url' ], self::PRIORITY_AFTER_URL_FILTERS, 3 );
			add_filter( 'wp_signup_location', [ $this, 'convert_url' ] );
			add_action( 'signup_hidden_fields', [ $this, 'add_signup_language_field' ] );

		}
	}

	public function add_signup_language_field() {
		echo "<input type='hidden' name='lang' value='" . $this->sitepress->get_current_language() . "' />";
	}

	public function redirect_to_login_url_with_lang() {
		$converted_url = site_url( $_SERVER['REQUEST_URI'], 'login' );
		if (
			! is_multisite()
			&& $converted_url != site_url( $_SERVER['REQUEST_URI'] )
			&& wp_redirect( $converted_url, 302, 'WPML' )
		) {
			exit;
		}
	}

	public function generate_rewrite_rules() {
		global $wp_rewrite;

		$language_rules = wpml_collect( Languages::getActive() )->mapWithKeys( function ( $lang ) {
			return [ $lang['code'] . '/wp-login.php' => 'wp-login.php' ];
		} );

		$wp_rewrite->non_wp_rules = array_merge( $language_rules->toArray(), $wp_rewrite->non_wp_rules );
	}

	public function filter_redirect_with_lang( $redirect_to ) {
		if ( ! $redirect_to && Obj::prop( 'lang', $_GET ) ) {
			$redirect_to = site_url( 'wp-login.php?checkemail=confirm', 'login' );
		}

		return $redirect_to;
	}

	public function wpml_login_page_language_from_url( $language, $url ) {
		if ( $this->is_wp_login_url( $url ) ) {
			if ( isset( $_GET['lang'] ) && $_GET['lang'] != $language ) {
				return filter_var( $_GET['lang'], FILTER_SANITIZE_STRING );
			}
			if ( is_multisite() && isset( $_POST['lang'] ) && $_POST['lang'] != $language ) {
				return filter_var( $_POST['lang'], FILTER_SANITIZE_STRING );
			}
		}

		return $language;
	}

	public function site_url( $url, $path, $scheme ) {
		if ( $scheme === 'login_post' || $scheme === 'login' || $this->should_convert_url_for_multisite( $url ) ) {
			$url = $this->convert_url( $url );
		}

		return $url;
	}

	public function convert_url( $url ) {
		$lang_param = $this->get_language_param_for_convert_url();
		if ( $lang_param ) {
			return add_query_arg( 'lang', $lang_param, $url );
		}

		return $this->url_converter->convert_url( $url );
	}

	public function on_request( $query_vars ) {
		if ( Relation::propEq( 'name', 'wp-login.php', $query_vars ) ) {
			$this->rewrite_rule_not_found = true;
		} else {
			$this->rewrite_rule_not_found = false;
		}

		if ( $this->rewrite_rule_not_found && $this->is_wp_login_action() ) {
			$current_url = site_url( $_SERVER['REQUEST_URI'], 'login' );
			$redirect_to = $this->remove_language_directory_from_url( $current_url );

			if (
				$redirect_to !== $current_url
				&& wp_redirect( $redirect_to, 302, 'WPML' )
			) {
				exit;
			}
		}

		return $query_vars;
	}

	private function should_convert_url_for_multisite( $url ) {
		return is_multisite() && Str::includes( 'wp-activate.php', $url );
	}

	private function is_wp_login_url( $url ) {
		return Str::includes( 'wp-login.php', $url )
		       || Str::includes( 'wp-signup.php', $url )
		       || Str::includes( 'wp-activate.php', $url );

	}

	private function is_wp_login_action() {
		$actions = wpml_collect( [
			'confirm_admin_email',
			'postpass',
			'logout',
			'lostpassword',
			'retrievepassword',
			'resetpass',
			'rp',
			'register',
			'login',
			'confirmaction',
		] );

		return $actions->contains( Obj::prop( 'action', $_GET ) );
	}

	private function get_language_param_for_convert_url() {
		if ( isset( $_GET['lang'] ) ) {
			return filter_var( $_GET['lang'], FILTER_SANITIZE_STRING );
		}
		if ( is_multisite() && isset( $_POST['lang'] ) ) {
			return filter_var( $_POST['lang'], FILTER_SANITIZE_STRING );
		}
		if ( $this->rewrite_rule_not_found || $this->is_subdomain_multisite() ) {
			return $this->sitepress->get_current_language();
		}

		return null;
	}

	private function is_subdomain_multisite() {
		return is_multisite() && defined( 'SUBDOMAIN_INSTALL' ) && SUBDOMAIN_INSTALL;
	}

	private function remove_language_directory_from_url( $url ) {
		$lang = $this->get_language_param_for_convert_url();
		$url_parts = wpml_parse_url( $url );
		if ( $lang && Str::includes( '/' . $lang . '/', $url_parts['path'] ) ) {
			$url = Str::replace( '/' . $lang . '/', '/', $url );
		}

		return $url;
	}
}