<?php

namespace UltraguardPro\modules\loginlimiter;

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

use UltraguardPro\core\BaseController;
use UltraguardPro\core\DatabaseCrud;
use UltraguardPro\core\MailManager;
use UltraguardPro\core\Utils;
use UltraguardPro\Plugin;

class LoginUrlEngine extends BaseController {

    public function __construct( ?Plugin $plugin = null ) {
        parent::__construct( $plugin );
    }

    public function intercept_login_url(): void {
        $secret = $this->get_secret_path();
        if ( 'wp-login.php' === $secret ) {
            return;
        }

        $uri  = sanitize_textarea_field( wp_unslash( $_SERVER['REQUEST_URI'] ?? '' ) );
        $path = $this->normalise_request_path( $uri );

        if ( $this->is_admin_path( $path ) ) {
            return;
        }

        if ( $path === trim( $secret, '/' ) ) {
            $this->bootstrap_hidden_login();
            return;
        }

        $is_login_hit = $path === 'wp-login.php' || substr( $path, -13 ) === '/wp-login.php';
        if ( ! $is_login_hit ) {
            return;
        }

        $this->log_attempt( $uri, false );
        $this->maybe_auto_block();

        $action = (string) $this->plugin->settings->get_option( 'login_protect_original_action', '404' );
        if ( 'redirect_home' === $action ) {
            wp_safe_redirect( home_url( '/' ) );
            exit;
        }

        if ( 'redirect_custom' === $action ) {
            $target = trim( (string) $this->plugin->settings->get_option( 'login_protect_custom_redirect_url', '' ) );
            if ( $target ) {
                $this->log_attempt( $uri, true );
                wp_safe_redirect( esc_url_raw( $target ) );
                exit;
            }
        }

        status_header( 404 );
        nocache_headers();
        header( 'Content-Type: text/html; charset=' . get_bloginfo( 'charset' ) );
        echo '<!doctype html><html><head><meta charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '"><title>404</title></head><body></body></html>';
        exit;
    }

    public function filter_login_url( string $url, string $path = '' ): string {
        $secret = $this->get_secret_path();
        if ( 'wp-login.php' === $secret ) {
            return $url;
        }

        if ( strpos( $url, 'wp-login.php' ) !== false ) {
            $target     = home_url( '/' . trim( $secret, '/' ) . '/' );
            $query_args = $this->extract_login_query_args( $url, $path );

            if ( ! empty( $query_args ) ) {
                $target = add_query_arg( $query_args, $target );
            }

            return $target;
        }

        return $url;
    }

    public function get_secret_path(): string {
        $slug = sanitize_title( (string) $this->plugin->settings->get_option( 'login_protect_custom_path', '' ) );
        return strlen( $slug ) >= 6 ? $slug : 'wp-login.php';
    }

    public function generate_secret_path(): string {
        return 'access-' . strtolower( wp_generate_password( 6, false, false ) );
    }

    public function get_stats(): array {
        $today = gmdate( 'Y-m-d 00:00:00' );
        $week  = gmdate( 'Y-m-d H:i:s', strtotime( '-7 days' ) );
        $chart_rows = DatabaseCrud::get_daily_count( 'ultraguard_login_protect_stats', 'created_at' );
        $chart      = [];

        foreach ( $chart_rows as $row ) {
            $day = is_object( $row ) ? (string) ( $row->date ?? '' ) : (string) ( $row['date'] ?? '' );
            if ( '' === $day || strtotime( $day ) < strtotime( '-30 days' ) ) {
                continue;
            }

            $chart[] = [
                'day'   => $day,
                'total' => (int) ( is_object( $row ) ? ( $row->count ?? 0 ) : ( $row['count'] ?? 0 ) ),
            ];
        }

        return [
            'today'      => DatabaseCrud::count_since( 'ultraguard_login_protect_stats', [], 'created_at', $today ),
            'week'       => DatabaseCrud::count_since( 'ultraguard_login_protect_stats', [], 'created_at', $week ),
            'unique_ips' => DatabaseCrud::count_distinct_since( 'ultraguard_login_protect_stats', 'ip_address', [], 'created_at', $week ),
            'recent'     => DatabaseCrud::get_records( 'ultraguard_login_protect_stats', [
                'limit'       => 100,
                'orderby'     => 'created_at',
                'order'       => 'DESC',
                'output_type' => ARRAY_A,
            ] ),
            'chart'      => $chart,
        ];
    }

    public function clear_stats(): void {
        DatabaseCrud::delete_all( 'ultraguard_login_protect_stats' );
    }

    public function log_failed_attempt( string $username ): void {
        $this->log_attempt( 'wp-login.php?failed=' . rawurlencode( $username ), false );
    }

    private function log_attempt( string $uri, bool $redirected ): void {
        if ( ! $this->plugin->settings->get_option( 'login_protect_log_attempts', true ) ) {
            return;
        }

        $table = $this->getTable( 'login_protect_stats' );
        $ip    = Utils::get_client_ip();
        $country_code = strtoupper( (string) Utils::get_country_from_ip( $ip ) );
        if ( $table && method_exists( $table, 'insert' ) ) {
            $table->insert( [
                'ip_address'     => $ip,
                'attempted_url'  => sanitize_textarea_field( $uri ),
                'user_agent'     => sanitize_textarea_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ?? '' ) ),
                'country_code'   => ( 'XX' !== $country_code && preg_match( '/^[A-Z]{2}$/', $country_code ) ) ? $country_code : '',
                'was_redirected' => $redirected ? 1 : 0,
                'created_at'     => current_time( 'mysql', true ),
            ] );
        }

        if ( $this->plugin->settings->get_option( 'login_protect_notify_admin', false ) ) {
            $last_notice = (int) get_transient( 'ultraguard_login_protect_notice_sent' );
            if ( $last_notice < ( time() - 15 * MINUTE_IN_SECONDS ) ) {
                set_transient( 'ultraguard_login_protect_notice_sent', time(), 15 * MINUTE_IN_SECONDS );
                MailManager::notification( [
                    'to'        => get_option( 'admin_email' ),
                    'subject'   => __( 'UltraGuard Login Protect detected access to the old login URL', 'ultraguard-security-suite' ),
                    'title'     => __( 'Protected login URL hit detected', 'ultraguard-security-suite' ),
                    'message'   => __( 'Someone tried to access the old WordPress login URL and UltraGuard intercepted the request.', 'ultraguard-security-suite' ),
                    'tone'      => 'warning',
                    'details'   => [
                        __( 'Attempted URL', 'ultraguard-security-suite' ) => $uri,
                        __( 'IP Address', 'ultraguard-security-suite' )    => $ip,
                        __( 'Time', 'ultraguard-security-suite' )          => current_time( 'mysql', true ),
                    ],
                    'cta_url'   => admin_url( 'admin.php?page=ultraguard-security-suite-dashboard&ug_page=login-protect' ),
                    'cta_label' => __( 'Open Hidden Login', 'ultraguard-security-suite' ),
                ] );
            }
        }

        do_action( 'ultraguard_pro/login_protect/old_url_hit', [
            'ip_address'     => Utils::get_client_ip(),
            'attempted_url'  => sanitize_textarea_field( $uri ),
            'user_agent'     => sanitize_textarea_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ?? '' ) ),
            'was_redirected' => $redirected,
            'created_at'     => current_time( 'mysql', true ),
        ] );
    }

    private function maybe_auto_block(): void {
        if ( ! $this->plugin->settings->get_option( 'login_protect_auto_block', false ) ) {
            return;
        }

        $ip = Utils::get_client_ip();
        if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
            return;
        }

        $key  = 'login_protect_hits_' . md5( $ip . gmdate( 'YmdH' ) );
        $hits = (int) get_transient( $key ) + 1;
        set_transient( $key, $hits, HOUR_IN_SECONDS );

        if ( $hits >= max( 1, (int) $this->plugin->settings->get_option( 'login_protect_auto_block_threshold', 5 ) ) ) {
            do_action( 'ultraguard_pro/firewall/block_ip', $ip, 'login_protect', 'Repeated access to protected login URL' );
        }
    }

    private function normalise_request_path( string $uri ): string {
        $request_path = trim( (string) wp_parse_url( $uri, PHP_URL_PATH ), '/' );
        $home_path    = trim( (string) wp_parse_url( home_url( '/' ), PHP_URL_PATH ), '/' );

        if ( $home_path !== '' && strpos( $request_path, $home_path . '/' ) === 0 ) {
            $request_path = substr( $request_path, strlen( $home_path ) + 1 );
        }

        return trim( $request_path, '/' );
    }

    private function bootstrap_hidden_login(): void {
        if ( defined( 'LOGIN_PROTECT_BOOTSTRAPPED' ) ) {
            return;
        }

        define( 'LOGIN_PROTECT_BOOTSTRAPPED', true );

        global $pagenow;
        $pagenow = 'wp-login.php';

        $home_path   = trim( (string) wp_parse_url( home_url( '/' ), PHP_URL_PATH ), '/' );
        $login_path  = ( $home_path !== '' ? '/' . $home_path : '' ) . '/wp-login.php';
        $query       = (string) wp_parse_url( sanitize_textarea_field( wp_unslash( $_SERVER['REQUEST_URI'] ?? '' ) ), PHP_URL_QUERY );
        $request_uri = $login_path . ( $query !== '' ? '?' . $query : '' );

        $_SERVER['PHP_SELF']        = $login_path;
        $_SERVER['SCRIPT_NAME']     = $login_path;
        $_SERVER['REQUEST_URI']     = $request_uri;
        $_SERVER['SCRIPT_FILENAME'] = ABSPATH . 'wp-login.php';
        $_SERVER['QUERY_STRING']    = $query;

        require_once ABSPATH . 'wp-login.php';
        exit;
    }

    private function extract_login_query_args( string $url, string $path = '' ): array {
        $query_args = [];

        $url_query = (string) wp_parse_url( $url, PHP_URL_QUERY );
        if ( $url_query !== '' ) {
            wp_parse_str( $url_query, $query_args );
        }

        if ( $path !== '' ) {
            $path_query = (string) wp_parse_url( $path, PHP_URL_QUERY );
            if ( $path_query !== '' ) {
                $path_args = [];
                wp_parse_str( $path_query, $path_args );
                $query_args = array_merge( $query_args, $path_args );
            } elseif ( strpos( $path, '?' ) === false && ! isset( $query_args['redirect_to'] ) ) {
                $query_args['redirect_to'] = $path;
            }
        }

        foreach ( $query_args as $key => $value ) {
            if ( is_array( $value ) ) {
                $query_args[ $key ] = array_map( 'sanitize_text_field', $value );
                continue;
            }

            $query_args[ $key ] = sanitize_text_field( (string) $value );
        }

        return $query_args;
    }

    private function is_admin_path( string $path ): bool {
        return $path === 'wp-admin' || substr( $path, -9 ) === '/wp-admin' || strpos( $path, 'wp-admin/' ) !== false;
    }
}
