<?php

defined( 'ABSPATH' ) || exit;

class ZACLS_Risk_Scoring {

	const TOR_EXIT_NODES_URL = 'https://check.torproject.org/torbulkexitlist';

	public static function score_login( $user_id = 0, $ip = '' ) {
		if ( empty( $ip ) ) {
			$ip = ZACLS_Main::get_ip();
		}

		$score      = 0;
		$factors    = array();
		$max_score  = 100;

		$ip_reputation = self::check_ip_reputation( $ip );
		$score        += $ip_reputation['score'];
		if ( $ip_reputation['score'] > 0 ) {
			$factors[] = $ip_reputation;
		}

		$is_new_device = self::check_new_device( $user_id );
		if ( $is_new_device['score'] > 0 ) {
			$score   += $is_new_device['score'];
			$factors[] = $is_new_device;
		}

		if ( ! empty( $user_id ) ) {
			$failed_attempts = self::check_failed_attempts( $user_id );
			if ( $failed_attempts['score'] > 0 ) {
				$score   += $failed_attempts['score'];
				$factors[] = $failed_attempts;
			}
		}

		$is_tor = self::check_tor( $ip );
		if ( $is_tor['score'] > 0 ) {
			$score   += $is_tor['score'];
			$factors[] = $is_tor;
		}

		$country = ZACLS_Main::lookup_country( $ip );
		if ( ! empty( $country ) ) {
			$geo_check = self::check_geolocation( $country, $user_id );
			if ( $geo_check['score'] > 0 ) {
				$score   += $geo_check['score'];
				$factors[] = $geo_check;
			}
		}

		$score = max( 0, min( $max_score, $score ) );

		$level = 'low';
		if ( $score >= 70 ) {
			$level = 'critical';
		} elseif ( $score >= 40 ) {
			$level = 'high';
		} elseif ( $score >= 15 ) {
			$level = 'medium';
		}

		return array(
			'score'       => $score,
			'level'       => $level,
			'max_score'   => $max_score,
			'factors'     => $factors,
			'timestamp'   => current_time( 'mysql' ),
		);
	}

	private static function check_ip_reputation( $ip ) {
		$blocked = ZACLS_IP_Blocker::is_ip_blocked( $ip );
		if ( $blocked ) {
			return array(
				'factor' => 'ip_reputation',
				'label'  => esc_html__( 'IP is blocked', 'za-creative-login-shield' ),
				'score'  => 40,
			);
		}

		global $wpdb;
		$failed_count = (int) $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->prefix}zacls_login_attempts
				WHERE ip = %s AND status = 'failed' AND attempt_time >= %s - INTERVAL 24 HOUR",
				$ip,
				current_time( 'mysql' )
			)
		);

		if ( $failed_count >= 20 ) {
			return array(
				'factor' => 'ip_reputation',
				'label'  => sprintf( esc_html__( 'High failed attempt rate from IP (%d in 24h)', 'za-creative-login-shield' ), $failed_count ),
				'score'  => 25,
			);
		}
		if ( $failed_count >= 5 ) {
			return array(
				'factor' => 'ip_reputation',
				'label'  => sprintf( esc_html__( 'Failed attempts detected from IP (%d in 24h)', 'za-creative-login-shield' ), $failed_count ),
				'score'  => 10,
			);
		}

		return array( 'factor' => 'ip_reputation', 'label' => '', 'score' => 0 );
	}

	private static function check_new_device( $user_id ) {
		if ( empty( $user_id ) || ! ZACLS_Device::is_enabled() ) {
			return array( 'factor' => 'new_device', 'label' => '', 'score' => 0 );
		}

		$device = new ZACLS_Device();
		if ( ! $device->is_device_recognized( $user_id ) ) {
			return array(
				'factor' => 'new_device',
				'label'  => esc_html__( 'New device detected', 'za-creative-login-shield' ),
				'score'  => 15,
			);
		}

		if ( ! $device->is_device_trusted( $user_id ) ) {
			return array(
				'factor' => 'new_device',
				'label'  => esc_html__( 'Untrusted device', 'za-creative-login-shield' ),
				'score'  => 5,
			);
		}

		return array( 'factor' => 'new_device', 'label' => '', 'score' => 0 );
	}

	private static function check_failed_attempts( $user_id ) {
		global $wpdb;

		$count = (int) $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->prefix}zacls_login_attempts
				WHERE user_id = %d AND status = 'failed' AND attempt_time >= %s - INTERVAL 1 HOUR",
				$user_id,
				current_time( 'mysql' )
			)
		);

		if ( $count >= 10 ) {
			return array(
				'factor' => 'failed_attempts',
				'label'  => sprintf( esc_html__( 'High failed attempts for user (%d in 1h)', 'za-creative-login-shield' ), $count ),
				'score'  => 30,
			);
		}
		if ( $count >= 3 ) {
			return array(
				'factor' => 'failed_attempts',
				'label'  => sprintf( esc_html__( 'Recent failed attempts for user (%d in 1h)', 'za-creative-login-shield' ), $count ),
				'score'  => 10,
			);
		}

		return array( 'factor' => 'failed_attempts', 'label' => '', 'score' => 0 );
	}

	private static function check_tor( $ip ) {
		if ( 'yes' !== get_option( 'zacls_tor_detection', 'no' ) ) {
			return array( 'factor' => 'tor', 'label' => '', 'score' => 0 );
		}

		$cached = get_transient( 'zacls_tor_nodes' );
		if ( false === $cached ) {
			$response = wp_remote_get( self::TOR_EXIT_NODES_URL, array( 'timeout' => 10 ) );
			if ( ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response ) ) {
				$nodes  = explode( "\n", trim( wp_remote_retrieve_body( $response ) ) );
				$cached = $nodes;
				set_transient( 'zacls_tor_nodes', $nodes, HOUR_IN_SECONDS * 6 );
			} else {
				return array( 'factor' => 'tor', 'label' => '', 'score' => 0 );
			}
		}

		if ( is_array( $cached ) && in_array( $ip, $cached, true ) ) {
			return array(
				'factor' => 'tor',
				'label'  => esc_html__( 'TOR exit node detected', 'za-creative-login-shield' ),
				'score'  => 30,
			);
		}

		return array( 'factor' => 'tor', 'label' => '', 'score' => 0 );
	}

	private static function check_geolocation( $country, $user_id ) {
		if ( empty( $user_id ) || 'yes' !== get_option( 'zacls_geoip_enabled', 'no' ) ) {
			return array( 'factor' => 'geolocation', 'label' => '', 'score' => 0 );
		}

		$last_country = get_user_meta( $user_id, 'zacls_last_country', true );
		if ( ! empty( $last_country ) && $last_country !== $country ) {
			return array(
				'factor' => 'geolocation',
				'label'  => sprintf( esc_html__( 'Login from different country (was: %s)', 'za-creative-login-shield' ), $last_country ),
				'score'  => 20,
			);
		}

		update_user_meta( $user_id, 'zacls_last_country', $country );
		return array( 'factor' => 'geolocation', 'label' => '', 'score' => 0 );
	}

	public static function get_level_class( $level ) {
		$map = array(
			'low'      => 'status-success',
			'medium'   => 'status-manual',
			'high'     => 'status-failed',
			'critical' => 'status-auto',
		);
		return $map[ $level ] ?? 'status-success';
	}
}
