<?php

/**
 * LinkCentral Link Manager Class
 *
 * This class handles the shared logic for creating, updating, and deleting LinkCentral links.
 * It provides consistent validation, sanitization, and business logic for both the admin interface
 * and REST API endpoints.
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
// Exit if accessed directly
class LinkCentral_Link_Manager {
    /**
     * Valid options for link attributes
     * @var array
     */
    private $valid_options = [
        'nofollow'             => ['default', 'yes', 'no'],
        'sponsored'            => ['default', 'yes', 'no'],
        'redirection_type'     => [
            'default',
            '307',
            '302',
            '301'
        ],
        'parameter_forwarding' => ['default', 'yes', 'no'],
        'css_classes_option'   => ['default', 'replace', 'append'],
    ];

    /**
     * Validate link data
     *
     * @param array $data Link data to validate
     * @param string $context Context of validation ('admin', 'rest_api')
     * @param int $post_id Post ID for updates (0 for new posts)
     * @return WP_Error|true Returns true if valid, WP_Error if invalid
     */
    public function validate_link_data( $data, $context = 'admin', $post_id = 0 ) {
        $errors = new WP_Error();
        $is_update = $post_id > 0;
        // For new links, require essential fields
        if ( !$is_update ) {
            if ( empty( $data['title'] ) ) {
                $errors->add( 'missing_title', __( 'Error: A title is required.', 'linkcentral' ) );
            }
            if ( empty( $data['slug'] ) ) {
                $errors->add( 'missing_slug', __( 'Error: A slug is required.', 'linkcentral' ) );
            }
            if ( empty( $data['destination_url'] ) ) {
                $errors->add( 'missing_destination_url', __( 'Error: A destination URL is required.', 'linkcentral' ) );
            } else {
                $sanitized_url = linkcentral_sanitize_destination_url( $data['destination_url'] );
                if ( $sanitized_url === 'https://' || empty( $sanitized_url ) ) {
                    $errors->add( 'invalid_destination_url', __( 'Error: A valid destination URL is required.', 'linkcentral' ) );
                }
            }
        } else {
            // For updates, only validate fields that are provided
            if ( isset( $data['title'] ) && empty( $data['title'] ) ) {
                $errors->add( 'missing_title', __( 'Error: A title is required.', 'linkcentral' ) );
            }
            if ( isset( $data['slug'] ) && empty( $data['slug'] ) ) {
                $errors->add( 'missing_slug', __( 'Error: A slug is required.', 'linkcentral' ) );
            }
            if ( isset( $data['destination_url'] ) ) {
                if ( empty( $data['destination_url'] ) ) {
                    $errors->add( 'missing_destination_url', __( 'Error: A destination URL is required.', 'linkcentral' ) );
                } else {
                    $sanitized_url = linkcentral_sanitize_destination_url( $data['destination_url'] );
                    if ( $sanitized_url === 'https://' || empty( $sanitized_url ) ) {
                        $errors->add( 'invalid_destination_url', __( 'Error: A valid destination URL is required.', 'linkcentral' ) );
                    }
                }
            }
        }
        // Validate link attribute options
        $fields_to_validate = ['nofollow', 'sponsored', 'redirection_type'];
        foreach ( $fields_to_validate as $field ) {
            if ( isset( $data[$field] ) && !empty( $data[$field] ) ) {
                if ( !in_array( $data[$field], $this->valid_options[$field], true ) ) {
                    /* translators: %s: Field name */
                    $errors->add( "invalid_{$field}", sprintf( __( 'Error: Invalid value for %s.', 'linkcentral' ), $field ) );
                }
            }
        }
        // Validate slug uniqueness
        if ( !empty( $data['slug'] ) ) {
            $unique_slug = $this->get_unique_slug( $data['slug'], $post_id );
            if ( $unique_slug !== $data['slug'] ) {
                // For REST API, we could auto-correct the slug
                if ( $context === 'rest_api' ) {
                    // This is informational - we'll use the unique slug
                } else {
                    // For admin, we might want to warn but still allow
                }
            }
        }
        return ( $errors->has_errors() ? $errors : true );
    }

    /**
     * Sanitize link data
     *
     * @param array $data Raw link data
     * @return array Sanitized link data
     */
    public function sanitize_link_data( $data ) {
        $sanitized = [];
        // Sanitize basic fields - only include if they exist in the data
        if ( isset( $data['title'] ) ) {
            $sanitized['title'] = sanitize_text_field( $data['title'] );
        }
        if ( isset( $data['slug'] ) ) {
            $sanitized['slug'] = linkcentral_sanitize_input_slug( $data['slug'] );
        }
        if ( isset( $data['destination_url'] ) ) {
            $sanitized['destination_url'] = linkcentral_sanitize_destination_url( $data['destination_url'] );
        }
        if ( isset( $data['note'] ) ) {
            $sanitized['note'] = sanitize_textarea_field( $data['note'] );
        }
        // Sanitize and validate link attributes
        $attribute_fields = ['nofollow', 'sponsored', 'redirection_type'];
        foreach ( $attribute_fields as $field ) {
            if ( isset( $data[$field] ) ) {
                $value = sanitize_text_field( $data[$field] );
                // Validate against allowed options
                if ( isset( $this->valid_options[$field] ) && in_array( $value, $this->valid_options[$field], true ) ) {
                    $sanitized[$field] = $value;
                } else {
                    $sanitized[$field] = 'default';
                }
            }
        }
        // Boolean fields - only include if they exist in the data
        if ( isset( $data['disable_slug_prefix'] ) ) {
            $sanitized['disable_slug_prefix'] = (bool) $data['disable_slug_prefix'];
        }
        return $sanitized;
    }

    /**
     * Create a new link
     *
     * @param array $data Link data
     * @return int|WP_Error Post ID on success, WP_Error on failure
     */
    public function create_link( $data ) {
        // Validate data first
        $validation_result = $this->validate_link_data( $data, 'rest_api' );
        if ( is_wp_error( $validation_result ) ) {
            return $validation_result;
        }
        // Sanitize data
        $sanitized_data = $this->sanitize_link_data( $data );
        // Ensure unique slug
        $sanitized_data['slug'] = $this->get_unique_slug( $sanitized_data['slug'], 0 );
        // Create the post
        $post_data = [
            'post_title'  => $sanitized_data['title'],
            'post_name'   => $sanitized_data['slug'],
            'post_type'   => 'linkcentral_link',
            'post_status' => 'publish',
        ];
        $post_id = wp_insert_post( $post_data );
        if ( is_wp_error( $post_id ) ) {
            return $post_id;
        }
        // Save meta data
        $this->save_link_meta( $post_id, $sanitized_data );
        return $post_id;
    }

    /**
     * Update an existing link
     *
     * @param int $post_id Post ID
     * @param array $data Link data
     * @return bool|WP_Error True on success, WP_Error on failure
     */
    public function update_link( $post_id, $data ) {
        // Check if post exists and is correct type
        $post = get_post( $post_id );
        if ( !$post || $post->post_type !== 'linkcentral_link' ) {
            return new WP_Error('invalid_post', __( 'Invalid link ID.', 'linkcentral' ));
        }
        // Validate data
        $validation_result = $this->validate_link_data( $data, 'rest_api', $post_id );
        if ( is_wp_error( $validation_result ) ) {
            return $validation_result;
        }
        // Sanitize data
        $sanitized_data = $this->sanitize_link_data( $data );
        // Ensure unique slug (if slug is being updated)
        if ( isset( $sanitized_data['slug'] ) ) {
            $sanitized_data['slug'] = $this->get_unique_slug( $sanitized_data['slug'], $post_id );
        }
        // Update post data if needed
        $update_post_data = false;
        $post_data = [];
        if ( isset( $sanitized_data['title'] ) && $sanitized_data['title'] !== $post->post_title ) {
            $post_data['post_title'] = $sanitized_data['title'];
            $update_post_data = true;
        }
        if ( isset( $sanitized_data['slug'] ) && $sanitized_data['slug'] !== $post->post_name ) {
            $post_data['post_name'] = $sanitized_data['slug'];
            $update_post_data = true;
        }
        if ( $update_post_data ) {
            $post_data['ID'] = $post_id;
            $result = wp_update_post( $post_data );
            if ( is_wp_error( $result ) ) {
                return $result;
            }
        }
        // Save meta data
        $this->save_link_meta( $post_id, $sanitized_data );
        return true;
    }

    /**
     * Clean up a link's associated data when permanently deleted
     *
     * @param int $post_id Post ID
     * @return bool|WP_Error True on success, WP_Error on failure
     */
    public function cleanup_link_on_delete( $post_id ) {
        return $this->cleanup_link_data( $post_id, true );
    }

    /**
     * Clean up a link's associated data when moved to trash
     *
     * @param int $post_id Post ID
     * @return bool|WP_Error True on success, WP_Error on failure
     */
    public function cleanup_link_on_trash( $post_id ) {
        return $this->cleanup_link_data( $post_id, false );
    }

    /**
     * Clean up a link's associated data
     *
     * @param int $post_id Post ID
     * @param bool $permanent_deletion Whether this is a permanent deletion (vs trashing)
     * @return bool|WP_Error True on success, WP_Error on failure
     */
    private function cleanup_link_data( $post_id, $permanent_deletion = false ) {
        // Check if post exists and is correct type
        $post = get_post( $post_id );
        if ( !$post || $post->post_type !== 'linkcentral_link' ) {
            return new WP_Error('invalid_post', __( 'Invalid link ID.', 'linkcentral' ));
        }
        // Delete tracking data (including keywords) only on permanent deletion
        if ( $permanent_deletion && get_option( 'linkcentral_delete_tracking_data_on_link_deletion', true ) ) {
            $this->delete_tracking_data( $post_id );
        }
        // Clean up broken links data on both trash and permanent deletion
        if ( class_exists( 'LinkCentral_Broken_Links_Checker' ) ) {
            LinkCentral_Broken_Links_Checker::cleanup_broken_link_data( $post_id );
        }
        return true;
    }

    /**
     * Save link meta data
     *
     * @param int $post_id Post ID
     * @param array $data Sanitized link data
     */
    public function save_link_meta( $post_id, $data ) {
        // Basic meta fields
        $meta_fields = [
            'destination_url',
            'nofollow',
            'sponsored',
            'redirection_type',
            'note'
        ];
        foreach ( $meta_fields as $field ) {
            if ( isset( $data[$field] ) ) {
                if ( $field === 'destination_url' && $data[$field] === 'https://' ) {
                    delete_post_meta( $post_id, "_linkcentral_{$field}" );
                } else {
                    update_post_meta( $post_id, "_linkcentral_{$field}", $data[$field] );
                }
            }
        }
        // Boolean fields
        if ( isset( $data['disable_slug_prefix'] ) ) {
            update_post_meta( $post_id, '_linkcentral_disable_slug_prefix', $data['disable_slug_prefix'] );
        }
    }

    /**
     * Save keywords for auto-keyword linking
     *
     * @param int $post_id Post ID
     * @param array $keywords Array of keyword objects with 'keyword' and 'density' properties
     * @return bool Success status
     */
    public function save_keywords( $post_id, $keywords ) {
        global $wpdb;
        $table_name = $wpdb->prefix . 'linkcentral_keywords';
        // Delete existing keywords for this link
        $wpdb->delete( $table_name, array(
            'link_id' => $post_id,
        ), array('%d') );
        // Ensure keywords is an array
        if ( !is_array( $keywords ) ) {
            return false;
        }
        // Save keywords
        foreach ( $keywords as $keyword_data ) {
            if ( is_array( $keyword_data ) && isset( $keyword_data['keyword'] ) && is_string( $keyword_data['keyword'] ) && !empty( trim( $keyword_data['keyword'] ) ) ) {
                $density = ( isset( $keyword_data['density'] ) && is_string( $keyword_data['density'] ) ? $keyword_data['density'] : 'medium' );
                // Validate density
                if ( !in_array( $density, ['low', 'medium', 'high'], true ) ) {
                    $density = 'medium';
                }
                $result = $wpdb->insert( $table_name, array(
                    'link_id' => $post_id,
                    'keyword' => trim( $keyword_data['keyword'] ),
                    'density' => $density,
                ), array('%d', '%s', '%s') );
                if ( $result === false ) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Delete tracking data for a link
     *
     * @param int $post_id Post ID
     */
    private function delete_tracking_data( $post_id ) {
        global $wpdb;
        // Delete tracking data
        $stats_table = $wpdb->prefix . 'linkcentral_stats';
        $wpdb->delete( $stats_table, array(
            'link_id' => $post_id,
        ) );
        // Delete keywords
        $keywords_table = $wpdb->prefix . 'linkcentral_keywords';
        $wpdb->delete( $keywords_table, array(
            'link_id' => $post_id,
        ), array('%d') );
    }

    /**
     * Clear broken links data when URL fields are being updated
     *
     * @param int $post_id Post ID
     * @param array $data Link data being saved
     */
    private function clear_changed_broken_links( $post_id, $data ) {
        // Check if URL fields are being updated
        $url_fields_being_saved = isset( $data['destination_url'] ) || isset( $data['dynamic_rules'] );
        if ( !$url_fields_being_saved ) {
            return;
        }
        // Get current broken links data
        $broken_links_data = get_option( 'linkcentral_broken_links', array() );
        if ( !isset( $broken_links_data[$post_id] ) ) {
            return;
        }
        // Clear all broken links data for this link
        unset($broken_links_data[$post_id]);
        update_option( 'linkcentral_broken_links', $broken_links_data );
    }

    /**
     * Sanitize variable values, handling different data types
     *
     * @param mixed $value The value to sanitize
     * @param string $variable_type The type of variable (country, device, etc.)
     * @return mixed The sanitized value
     */
    private function sanitize_variable_value( $value, $variable_type = null ) {
        if ( is_array( $value ) ) {
            // Handle simple arrays (like country, device selections)
            if ( isset( $value[0] ) && !is_array( $value[0] ) ) {
                return array_map( 'sanitize_text_field', $value );
            }
            // Handle nested arrays
            return array_map( array($this, 'sanitize_variable_value'), $value );
        } elseif ( is_object( $value ) || is_array( $value ) && !isset( $value[0] ) ) {
            // Handle objects/associative arrays (like logged_in_status)
            $sanitized_object = [];
            foreach ( $value as $key => $val ) {
                $sanitized_key = sanitize_text_field( $key );
                $sanitized_object[$sanitized_key] = $this->sanitize_variable_value( $val );
            }
            return $sanitized_object;
        } else {
            // Handle simple values
            $sanitized_value = sanitize_text_field( $value );
            // Ensure certain variable types are always arrays
            if ( in_array( $variable_type, ['country', 'device'] ) && !empty( $sanitized_value ) ) {
                return [$sanitized_value];
            }
            return $sanitized_value;
        }
    }

    /**
     * Get a unique slug for LinkCentral links while preserving forward slashes
     *
     * @param string $slug The desired slug
     * @param int $post_id The post ID
     * @return string The unique slug
     */
    public function get_unique_slug( $slug, $post_id ) {
        global $wpdb;
        $original_slug = $slug;
        // Check if the slug already exists for a different post
        $check_sql = "SELECT ID FROM {$wpdb->posts} WHERE post_name = %s AND post_type = %s AND ID != %d LIMIT 1";
        $existing_post = $wpdb->get_var( $wpdb->prepare(
            $check_sql,
            $slug,
            'linkcentral_link',
            $post_id
        ) );
        if ( !$existing_post ) {
            return $slug;
        }
        // If slug exists, append a number to make it unique
        $suffix = 2;
        do {
            $alt_slug = $original_slug . '-' . $suffix;
            $existing_post = $wpdb->get_var( $wpdb->prepare(
                $check_sql,
                $alt_slug,
                'linkcentral_link',
                $post_id
            ) );
            $suffix++;
        } while ( $existing_post );
        return $alt_slug;
    }

    /**
     * Get link data by ID
     *
     * @param int $post_id Post ID
     * @return array|WP_Error Link data array or WP_Error if not found
     */
    public function get_link_data( $post_id ) {
        $post = get_post( $post_id );
        if ( !$post || $post->post_type !== 'linkcentral_link' ) {
            return new WP_Error('invalid_post', __( 'Invalid link ID.', 'linkcentral' ));
        }
        $data = [
            'id'                  => $post->ID,
            'title'               => $post->post_title,
            'slug'                => $post->post_name,
            'destination_url'     => get_post_meta( $post->ID, '_linkcentral_destination_url', true ),
            'nofollow'            => get_post_meta( $post->ID, '_linkcentral_nofollow', true ),
            'sponsored'           => get_post_meta( $post->ID, '_linkcentral_sponsored', true ),
            'redirection_type'    => get_post_meta( $post->ID, '_linkcentral_redirection_type', true ),
            'note'                => get_post_meta( $post->ID, '_linkcentral_note', true ),
            'disable_slug_prefix' => get_post_meta( $post->ID, '_linkcentral_disable_slug_prefix', true ),
        ];
        return $data;
    }

}
