<?php

/**
 * LinkCentral Link Helpers
 *
 * This file contains helper functions for LinkCentral links, such as getting the complete URL for a link and sanitizing slugs.
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
// Exit if accessed directly
/**
 * Sanitize LinkCentral slug/post name while preserving forward slashes
 *
 * @param string $input The input string to sanitize
 * @param array $options Optional parameters to control sanitization behavior
 *                      'for_input' => bool - True for input sanitization (more permissive), false for output (more restrictive)
 *                      'to_lowercase' => bool - Whether to convert to lowercase (default: true for input, false for output)
 *                      'remove_path_traversal' => bool - Whether to remove .. sequences (default: true)
 *                      'trim_slashes' => bool - Whether to trim leading/trailing slashes (default: true)
 * @return string The sanitized string
 */
function linkcentral_sanitize_slug(  $input, $options = array()  ) {
    // Default options
    $defaults = array(
        'for_input'             => true,
        'to_lowercase'          => null,
        'remove_path_traversal' => true,
        'trim_slashes'          => true,
    );
    $options = wp_parse_args( $options, $defaults );
    // Set lowercase default based on context
    if ( $options['to_lowercase'] === null ) {
        $options['to_lowercase'] = $options['for_input'];
    }
    $sanitized = $input;
    // Convert to lowercase if requested (typically for input)
    if ( $options['to_lowercase'] ) {
        $sanitized = strtolower( $sanitized );
    }
    // Remove path traversal attempts
    if ( $options['remove_path_traversal'] ) {
        $sanitized = str_replace( '..', '', $sanitized );
    }
    if ( $options['for_input'] ) {
        // Input sanitization: replace invalid characters with hyphens, more permissive
        $sanitized = preg_replace( '/[^a-zA-Z0-9\\/\\-_]+/', '-', $sanitized );
        // Remove leading and trailing hyphens and slashes
        if ( $options['trim_slashes'] ) {
            $sanitized = trim( $sanitized, '-/' );
        }
        // Replace multiple consecutive hyphens with a single hyphen
        $sanitized = preg_replace( '/-+/', '-', $sanitized );
    } else {
        // Output sanitization: remove invalid characters completely, more restrictive
        $sanitized = preg_replace( '/[^a-zA-Z0-9\\-_\\/]/', '', $sanitized );
        // Remove leading and trailing slashes only
        if ( $options['trim_slashes'] ) {
            $sanitized = trim( $sanitized, '/' );
        }
    }
    // Replace multiple consecutive forward slashes with a single forward slash
    $sanitized = preg_replace( '/\\/+/', '/', $sanitized );
    return $sanitized;
}

/**
 * Sanitize LinkCentral slug for input (when creating/editing posts)
 * 
 * @param string $slug The slug to sanitize
 * @return string The sanitized slug
 */
function linkcentral_sanitize_input_slug(  $slug  ) {
    return linkcentral_sanitize_slug( $slug, array(
        'for_input'             => true,
        'to_lowercase'          => false,
        'remove_path_traversal' => true,
        'trim_slashes'          => true,
    ) );
}

/**
 * Sanitize LinkCentral post name for URL output (when generating URLs)
 * 
 * @param string $post_name The post name to sanitize
 * @return string The sanitized post name
 */
function linkcentral_sanitize_output_slug(  $post_name  ) {
    return linkcentral_sanitize_slug( $post_name, array(
        'for_input'             => false,
        'to_lowercase'          => false,
        'remove_path_traversal' => true,
        'trim_slashes'          => true,
    ) );
}

/**
 * Get the complete URL for a LinkCentral link
 * 
 * @param int $link_id The link ID
 * @param string $post_name Optional post name (will be fetched if not provided)
 * @return string The complete URL for the link
 */
function linkcentral_get_link_url(  $link_id, $post_name = null  ) {
    if ( empty( $post_name ) ) {
        $link = get_post( $link_id );
        if ( !$link || $link->post_type !== 'linkcentral_link' ) {
            return '';
        }
        $post_name = $link->post_name;
    }
    $disable_slug_prefix = get_post_meta( $link_id, '_linkcentral_disable_slug_prefix', true );
    $sanitized_slug = linkcentral_sanitize_output_slug( $post_name );
    if ( $disable_slug_prefix ) {
        return home_url( '/' . $sanitized_slug );
    } else {
        $url_prefix = get_option( 'linkcentral_url_prefix', 'go' );
        return home_url( '/' . $url_prefix . '/' . $sanitized_slug );
    }
}

/**
 * Sanitize destination URL for LinkCentral links
 * More forgiving than esc_url_raw to support custom schemes, relative paths, and special protocols
 *
 * @param string $url The URL to sanitize
 * @return string The sanitized URL
 */
function linkcentral_sanitize_destination_url(  $url  ) {
    $url = trim( $url );
    // Empty URLs return empty
    if ( empty( $url ) ) {
        return '';
    }
    // Remove any null bytes and control characters for security
    $url = str_replace( array(
        "\x00",
        "\r",
        "\n",
        "\t"
    ), '', $url );
    // Check if it's a standard HTTP/HTTPS URL - use WordPress sanitization for these
    if ( preg_match( '/^https?:\\/\\//', $url ) ) {
        return esc_url_raw( $url );
    }
    // For custom schemes and relative paths, do basic sanitization
    // Remove dangerous characters but preserve the structure
    $url = preg_replace( '/[<>"\'`\\s]/', '', $url );
    // Ensure it doesn't contain javascript: or data: schemes for security
    if ( preg_match( '/^(javascript|data|vbscript):/i', $url ) ) {
        return '';
    }
    return $url;
}

/**
 * Truncate long URLs for display in tables
 *
 * @param string $url The URL to truncate
 * @param int $max_length Maximum length (default: 50)
 * @return string HTML string with truncated URL and tooltip
 */
function linkcentral_truncate_url(  $url, $max_length = 100  ) {
    if ( empty( $url ) || strlen( $url ) <= $max_length ) {
        return esc_html( $url );
    }
    $truncated_text = substr( $url, 0, $max_length - 3 );
    return '<span class="linkcentral-truncated-url" data-full-url="' . esc_attr( $url ) . '">' . esc_html( $truncated_text ) . '<span class="linkcentral-truncate-dots">...</span></span>';
}

/**
 * LinkCentral Link Attributes Helper Class
 *
 * This class handles the common logic for processing link attributes like CSS classes,
 * nofollow, sponsored, and parameter forwarding that is used across multiple components.
 */
class LinkCentral_Link_Attributes {
    private $global_css_classes;

    private $global_nofollow;

    private $global_sponsored;

    private $global_parameter_forwarding;

    /**
     * Constructor - initialize global settings
     */
    public function __construct() {
        $this->global_css_classes = get_option( 'linkcentral_custom_css_classes', '' );
        $this->global_nofollow = get_option( 'linkcentral_global_nofollow', false );
        $this->global_sponsored = get_option( 'linkcentral_global_sponsored', false );
        $this->global_parameter_forwarding = get_option( 'linkcentral_global_parameter_forwarding', false );
    }

    /**
     * Get CSS classes for a link based on link data
     *
     * @param array $link_data Link data array containing css_classes_option and custom_css_classes
     * @return string CSS classes to apply
     */
    public function get_css_classes_from_data( $link_data ) {
        switch ( $link_data['css_classes_option'] ) {
            case 'replace':
                return $link_data['custom_css_classes'];
            case 'append':
                return trim( $this->global_css_classes . ' ' . $link_data['custom_css_classes'] );
            case 'default':
            default:
                return $this->global_css_classes;
        }
    }

    /**
     * Get CSS classes for a link based on link ID (for shortcode usage)
     *
     * @param int $link_id The link ID
     * @return string CSS classes to apply
     */
    public function get_css_classes_from_id( $link_id ) {
        $css_classes_option = get_post_meta( $link_id, '_linkcentral_css_classes_option', true );
        $custom_css_classes = get_post_meta( $link_id, '_linkcentral_custom_css_classes', true );
        switch ( $css_classes_option ) {
            case 'replace':
                return $custom_css_classes;
            case 'append':
                return $this->global_css_classes . ' ' . $custom_css_classes;
            case 'default':
            default:
                return $this->global_css_classes;
        }
    }

    /**
     * Get nofollow attribute for a link based on link data
     *
     * @param array $link_data Link data array containing nofollow setting
     * @return string 'nofollow' if should be applied, empty string otherwise
     */
    public function get_nofollow_from_data( $link_data ) {
        if ( $link_data['nofollow'] === 'yes' ) {
            return 'nofollow';
        } elseif ( $link_data['nofollow'] === 'no' ) {
            return '';
        } else {
            return ( $this->global_nofollow ? 'nofollow' : '' );
        }
    }

    /**
     * Get nofollow attribute for a link based on link ID (for shortcode usage)
     *
     * @param int $link_id The link ID
     * @return string 'nofollow' if should be applied, empty string otherwise
     */
    public function get_nofollow_from_id( $link_id ) {
        $nofollow = get_post_meta( $link_id, '_linkcentral_nofollow', true );
        if ( $nofollow === 'default' ) {
            $nofollow = ( $this->global_nofollow ? 'yes' : 'no' );
        }
        return ( $nofollow === 'yes' ? 'nofollow' : '' );
    }

    /**
     * Get sponsored attribute for a link based on link data
     *
     * @param array $link_data Link data array containing sponsored setting
     * @return string 'sponsored' if should be applied, empty string otherwise
     */
    public function get_sponsored_from_data( $link_data ) {
        if ( $link_data['sponsored'] === 'yes' ) {
            return 'sponsored';
        } elseif ( $link_data['sponsored'] === 'no' ) {
            return '';
        } else {
            return ( $this->global_sponsored ? 'sponsored' : '' );
        }
    }

    /**
     * Get sponsored attribute for a link based on link ID (for shortcode usage)
     *
     * @param int $link_id The link ID
     * @return string 'sponsored' if should be applied, empty string otherwise
     */
    public function get_sponsored_from_id( $link_id ) {
        $sponsored = get_post_meta( $link_id, '_linkcentral_sponsored', true );
        if ( $sponsored === 'default' ) {
            $sponsored = ( $this->global_sponsored ? 'yes' : 'no' );
        }
        return ( $sponsored === 'yes' ? 'sponsored' : '' );
    }

    /**
     * Get rel attributes array for a link based on link data
     *
     * @param array $link_data Link data array
     * @return array Array of rel attributes to apply
     */
    public function get_rel_attributes_from_data( $link_data ) {
        $rel_attributes = array();
        $nofollow = $this->get_nofollow_from_data( $link_data );
        if ( !empty( $nofollow ) ) {
            $rel_attributes[] = $nofollow;
        }
        $sponsored = $this->get_sponsored_from_data( $link_data );
        if ( !empty( $sponsored ) ) {
            $rel_attributes[] = $sponsored;
        }
        return $rel_attributes;
    }

    /**
     * Get rel attributes array for a link based on link ID (for shortcode usage)
     *
     * @param int $link_id The link ID
     * @return array Array of rel attributes to apply
     */
    public function get_rel_attributes_from_id( $link_id ) {
        $rel_attributes = array();
        $nofollow = $this->get_nofollow_from_id( $link_id );
        if ( !empty( $nofollow ) ) {
            $rel_attributes[] = $nofollow;
        }
        $sponsored = $this->get_sponsored_from_id( $link_id );
        if ( !empty( $sponsored ) ) {
            $rel_attributes[] = $sponsored;
        }
        return $rel_attributes;
    }

    /**
     * Build HTML attributes string for a link
     *
     * @param array $rel_attributes Array of rel attributes
     * @param string $css_classes CSS classes string
     * @param string $target Target attribute (optional)
     * @return string HTML attributes string
     */
    public function build_html_attributes( $rel_attributes = array(), $css_classes = '', $target = '' ) {
        $attributes = array();
        if ( !empty( $rel_attributes ) ) {
            $attributes[] = 'rel="' . esc_attr( implode( ' ', $rel_attributes ) ) . '"';
        }
        if ( !empty( $css_classes ) ) {
            $attributes[] = 'class="' . esc_attr( $css_classes ) . '"';
        }
        if ( !empty( $target ) ) {
            $attributes[] = 'target="' . esc_attr( $target ) . '"';
        }
        return implode( ' ', $attributes );
    }

}
