<?php
/**
 * LinkCentral ThirstyAffiliates Import Handler
 *
 * This trait handles ThirstyAffiliates database import functionality for LinkCentral links.
 * It can be used by any class that needs to import links from ThirstyAffiliates database.
 */

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

/**
 * Utility class for ThirstyAffiliates plugin detection and configuration
 */
class LinkCentral_ThirstyAffiliates_Utils {

    /**
     * Import configuration constants
     */
    const DEFAULT_BATCH_SIZE = 50;
    const STATS_BATCH_SIZE = 1000;
    const MAX_LINKS_PER_IMPORT = 1000;
    const MAX_CLICKS_PER_LINK = 50000;

    /**
     * Check if ThirstyAffiliates plugin is active
     *
     * @return bool True if ThirstyAffiliates is active
     */
    private static function is_plugin_active() {
        return function_exists('is_plugin_active') && is_plugin_active('thirstyaffiliates/thirstyaffiliates.php');
    }
    
    /**
     * Check if ThirstyAffiliates is available (active and has data)
     *
     * @return bool True if ThirstyAffiliates is active and has data
     */
    public static function is_available() {
        // Check if ThirstyAffiliates plugin is active first (cheapest check)
        if (!self::is_plugin_active()) {
            return false;
        }
        
        // Quick check if any ThirstyAffiliates links exist
        global $wpdb;
        $count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}posts WHERE post_type = 'thirstylink'");
        return $count > 0;
    }

    /**
     * Get ThirstyAffiliates URL prefix
     *
     * @return string The URL prefix used by ThirstyAffiliates
     */
    public static function get_thirstyaffiliates_prefix() {
        // Check if ThirstyAffiliates plugin is active first
        if (!self::is_plugin_active()) {
            return '';
        }

        // Get the URL prefix from ThirstyAffiliates
        $ta_prefix = get_option('ta_link_prefix', false);

        // Return empty string if option doesn't exist or is empty
        if ($ta_prefix === false || empty($ta_prefix)) {
            return '';
        }

        return $ta_prefix;
    }

    /**
     * Get ThirstyAffiliates statistics
     *
     * @return array Statistics about ThirstyAffiliates data
     */
    public static function get_stats() {
        // Check if ThirstyAffiliates plugin is active first
        if (!self::is_plugin_active()) {
            return array('links' => 0, 'categories' => 0, 'stats' => 0);
        }

        global $wpdb;

        // Single optimized query to get both total and published link counts
        $link_counts = $wpdb->get_row("
            SELECT
                COUNT(*) as total_links,
                SUM(CASE WHEN post_status = 'publish' THEN 1 ELSE 0 END) as published_links
            FROM {$wpdb->prefix}posts
            WHERE post_type = 'thirstylink'
        ", ARRAY_A);

        $total_links = (int) ($link_counts['total_links'] ?? 0);
        $published_links = (int) ($link_counts['published_links'] ?? 0);

        // If no ThirstyAffiliates data exists, return zeros
        if ($total_links === 0) {
            return array('links' => 0, 'categories' => 0, 'stats' => 0);
        }

        // Count categories (only if we have links)
        $categories_count = $wpdb->get_var("
            SELECT COUNT(DISTINCT t.term_id)
            FROM {$wpdb->prefix}terms t
            INNER JOIN {$wpdb->prefix}term_taxonomy tt ON t.term_id = tt.term_id
            WHERE tt.taxonomy = 'thirstylink-category'
        ");

        // Count stats (check if ThirstyAffiliates Pro table exists)
        $stats_count = 0;
        $stats_table = esc_sql($wpdb->prefix . 'ta_link_clicks');
        if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $stats_table)) === $stats_table) {
            $stats_count = $wpdb->get_var("SELECT COUNT(*) FROM `{$wpdb->prefix}ta_link_clicks`");
        }

        return array(
            'links' => $published_links,
            'categories' => (int) $categories_count,
            'stats' => (int) $stats_count
        );
    }
}

class LinkCentral_ThirstyAffiliates_Importer {

    /**
     * Check if ThirstyAffiliates plugin is installed
     *
     * @return bool True if ThirstyAffiliates is installed
     */
    public function is_available() {
        return LinkCentral_ThirstyAffiliates_Utils::is_available();
    }

    /**
     * Get ThirstyAffiliates statistics
     *
     * @return array Statistics about ThirstyAffiliates data
     */
    public function get_stats() {
        return LinkCentral_ThirstyAffiliates_Utils::get_stats();
    }

    /**
     * Process ThirstyAffiliates import
     *
     * @param array $import_options Import options
     * @return array|WP_Error Import results or error
     */
    public function process_import($import_options = array()) {
        global $wpdb;

        if (!$this->is_available()) {
            return new WP_Error('no_data', __('No ThirstyAffiliates data found.', 'linkcentral'));
        }

        $defaults = array(
            'update_url_prefix' => false,
            'import_categories' => false,
            'import_stats' => false,
            'duplicate_handling' => 'skip',
            'batch_size' => LinkCentral_ThirstyAffiliates_Utils::DEFAULT_BATCH_SIZE, // Process links at a time
            'offset' => 0 // For resuming imports
        );

        $import_options = wp_parse_args($import_options, $defaults);

        // Map ThirstyAffiliates-specific options to generic import options
        $import_options['create_categories'] = $import_options['import_categories'];

        // Resolve once: does ThirstyAffiliates have "show category in slug" enabled?
        $import_options['ta_show_cat_in_slug'] = get_option('ta_show_cat_in_slug') === 'yes';

        $results = array(
            'success' => 0,
            'skipped' => 0,
            'errors' => 0,
            'categories_imported' => 0,
            'stats_imported' => 0,
            'prefix_updated' => false,
            'skipped_links' => array(),
            'error_details' => array()
        );

        // Update URL prefix if requested
        if ($import_options['update_url_prefix']) {
            $ta_prefix = LinkCentral_ThirstyAffiliates_Utils::get_thirstyaffiliates_prefix();
            if (!empty($ta_prefix)) {
                update_option('linkcentral_url_prefix', $ta_prefix);
                $results['prefix_updated'] = true;
            }
        }

        // Import categories first if requested
        if ($import_options['import_categories']) {
            $category_result = $this->import_categories();
            $results['categories_imported'] = $category_result;
        }

        // Import links in batches
        $batch_size = $import_options['batch_size'];
        $offset = $import_options['offset'];
        $processed = 0;

        while (true) {
            $links = $this->get_links($batch_size, $offset);

            if (empty($links)) {
                break; // No more links to process
            }

            foreach ($links as $ta_link) {
                $link_result = $this->import_single_link($ta_link, $import_options);

                if (is_wp_error($link_result)) {
                    $results['errors']++;
                    $results['error_details'][] = array(
                        'link' => $ta_link['title'],
                        'error' => $link_result->get_error_message()
                    );
                } elseif ($link_result['action'] === 'skipped') {
                    $results['skipped']++;
                    LinkCentral_Import_Shared::add_skipped_link($results, $ta_link, array(
                        'existing_link' => $link_result['existing_link'] ?? null,
                    ));
                } else {
                    $results['success']++;

                    // Import stats if requested
                    if ($import_options['import_stats'] && isset($link_result['link_id'])) {
                        $stats_imported = $this->import_stats($ta_link['ID'], $link_result['link_id']);
                        $results['stats_imported'] += $stats_imported;
                    }
                }

                $processed++;
            }

            $offset += count($links);

            // Optional: Add progress tracking
            $results['processed'] = $processed;
            $results['current_offset'] = $offset;

            // Prevent infinite loops and timeouts
            if ($processed >= LinkCentral_ThirstyAffiliates_Utils::MAX_LINKS_PER_IMPORT) { // Safety limit
                $results['batch_complete'] = false;
                $results['resume_offset'] = $offset;
                break;
            }
        }

        $results['batch_complete'] = true;
        return $results;
    }

    /**
     * Get ThirstyAffiliates links from database
     *
     * @return array Array of ThirstyAffiliates links
     */
    private function get_links($batch_size = null, $offset = 0) {
        global $wpdb;

        // Build query with proper escaping
        if ($batch_size) {
            $links = $wpdb->get_results($wpdb->prepare("
                SELECT p.ID, p.post_title as title, p.post_name as slug, p.post_content as content, p.post_date
                FROM {$wpdb->prefix}posts p
                WHERE p.post_type = 'thirstylink'
                AND p.post_status = 'publish'
                ORDER BY p.post_date ASC
                LIMIT %d OFFSET %d
            ", $batch_size, $offset), ARRAY_A);
        } else {
            $links = $wpdb->get_results("
                SELECT p.ID, p.post_title as title, p.post_name as slug, p.post_content as content, p.post_date
                FROM {$wpdb->prefix}posts p
                WHERE p.post_type = 'thirstylink'
                AND p.post_status = 'publish'
                ORDER BY p.post_date ASC
            ", ARRAY_A);
        }

        // Get metadata for each link (optimized - only fetch specific keys)
        foreach ($links as &$link) {
            $link['destination_url'] = get_post_meta($link['ID'], '_ta_destination_url', true);
            $link['rel_tags'] = get_post_meta($link['ID'], '_ta_rel_tags', true);
            $link['redirect_type'] = get_post_meta($link['ID'], '_ta_redirect_type', true) ?: '302';
            $link['no_follow'] = get_post_meta($link['ID'], '_ta_no_follow', true);
            $link['new_window'] = get_post_meta($link['ID'], '_ta_new_window', true);
            $link['pass_query_str'] = get_post_meta($link['ID'], '_ta_pass_query_str', true);
            $link['ta_category_slug'] = get_post_meta($link['ID'], '_ta_category_slug', true);

            // Get categories with hierarchical structure
            $categories = wp_get_post_terms($link['ID'], 'thirstylink-category', array('fields' => 'all'));
            $link['categories'] = is_array($categories) ? $this->build_category_hierarchy($categories) : array();
        }

        return $links;
    }

    /**
     * Build hierarchical category paths from ThirstyAffiliates categories
     *
     * @param array $categories Array of WP_Term objects
     * @return array Array of hierarchical category paths like "Parent > Child"
     */
    private function build_category_hierarchy($categories) {
        $hierarchical_paths = array();

        foreach ($categories as $category) {
            $hierarchical_paths[] = $this->build_category_path($category);
        }

        return $hierarchical_paths;
    }

    /**
     * Build a hierarchical path from a category term
     *
     * @param WP_Term $category The category term
     * @return string Hierarchical path like "Parent > Child"
     */
    private function build_category_path($category) {
        $path_parts = array();
        $current_term = $category;

        // Walk up the hierarchy to build the full path
        while ($current_term) {
            array_unshift($path_parts, $current_term->name);
            if ($current_term->parent > 0) {
                $current_term = get_term($current_term->parent, 'thirstylink-category');
                if (is_wp_error($current_term) || !$current_term) {
                    break;
                }
            } else {
                break;
            }
        }

        return implode(' > ', $path_parts);
    }

    /**
     * Import ThirstyAffiliates categories
     *
     * @return int Number of categories imported
     */
    private function import_categories() {
        $ta_categories = get_terms(array(
            'taxonomy' => 'thirstylink-category',
            'hide_empty' => false,
        ));

        if (is_wp_error($ta_categories)) {
            return 0;
        }

        $imported_count = 0;

        // Sort categories by hierarchy (parents first)
        usort($ta_categories, function($a, $b) {
            return $a->parent - $b->parent;
        });

        foreach ($ta_categories as $ta_category) {
            // Build hierarchical path for this category
            $category_path = $this->get_category_hierarchical_path($ta_category);

            // Use the import utilities to handle hierarchical category creation
            $term_id = LinkCentral_Import_Shared::get_or_create_category($category_path, true);

            if ($term_id) {
                $imported_count++;
            }
        }

        return $imported_count;
    }

    /**
     * Get the hierarchical path for a ThirstyAffiliates category
     *
     * @param WP_Term $category The category term
     * @return string Hierarchical path like "Parent > Child"
     */
    private function get_category_hierarchical_path($category) {
        return $this->build_category_path($category);
    }

    /**
     * Import a single ThirstyAffiliates link
     *
     * @param array $ta_link ThirstyAffiliates link data
     * @param array $import_options Import options
     * @return array|WP_Error Import result or error
     */
    private function import_single_link($ta_link, $import_options) {
        // If ThirstyAffiliates has "show category in slug" enabled, prepend the resolved
        // category slug so the final slug mirrors the original TA URL structure.
        if (!empty($import_options['ta_show_cat_in_slug'])) {
            $cat_slug = $this->get_ta_category_slug($ta_link);
            if (!empty($cat_slug)) {
                $ta_link['slug'] = $cat_slug . '/' . $ta_link['slug'];
            }
        }

        // Process slug and prefix first to determine the final slug
        // This fixes duplicate detection when ThirstyAffiliates slug matches LinkCentral prefix
        $current_prefix = get_option('linkcentral_url_prefix', 'go');
        // If updating to ThirstyAffiliates prefix, don't force current prefix; otherwise force it
        $force_prefix = $import_options['force_prefix'] ?? !$import_options['update_url_prefix'];
        $slug_info = LinkCentral_Import_Shared::process_slug($ta_link['slug'], $current_prefix, $force_prefix);

        // Check for existing link by the processed slug (what the final slug will be)
        $existing_link = LinkCentral_Import_Shared::find_existing_link($slug_info['slug']);

        if ($existing_link && $import_options['duplicate_handling'] === 'skip') {
            return array(
                'action' => 'skipped',
                'existing_link' => $existing_link,
            );
        }

        // Prepare link data
        $link_data = array(
            'title' => $ta_link['title'],
            'destination_url' => $ta_link['destination_url'],
            'slug' => $slug_info['slug'],
            // When updating to ThirstyAffiliates prefix, ensure all links use the prefix
            'disable_slug_prefix' => $import_options['update_url_prefix'] ? false : $slug_info['disable_slug_prefix'],
            'category' => $import_options['import_categories'] ? $ta_link['categories'] : array(), // Only pass categories if importing them
            'nofollow' => $this->convert_ta_nofollow($ta_link['rel_tags'], $ta_link['no_follow']),
            'sponsored' => $this->convert_ta_sponsored($ta_link['rel_tags']),
            'parameter_forwarding' => $this->convert_ta_parameter_forwarding($ta_link['pass_query_str']),
            'redirect_type' => $this->convert_ta_redirect_type($ta_link['redirect_type']),
            'note' => $ta_link['content'],
            'keywords' => ''
        );
        
        // Validate required fields
        $validation_result = LinkCentral_Import_Shared::validate_link_data($link_data);
        if (is_wp_error($validation_result)) {
            return $validation_result;
        }
        
        // Create or update the link
        $link_result = LinkCentral_Import_Shared::create_or_update_link($link_data, $existing_link, $import_options);
        
        if (is_wp_error($link_result)) {
            return $link_result;
        }
        
        return array(
            'action' => $existing_link ? 'updated' : 'created',
            'link_id' => $link_result
        );
    }

    /**
     * Import ThirstyAffiliates stats for a link
     *
     * @param int $ta_link_id ThirstyAffiliates link ID
     * @param int $lc_link_id LinkCentral link ID
     * @return int Number of stats imported
     */
    private function import_stats($ta_link_id, $lc_link_id) {
        global $wpdb;

        $stats_table = esc_sql($wpdb->prefix . 'ta_link_clicks');
        $stats_meta_table = esc_sql($wpdb->prefix . 'ta_link_clicks_meta');

        // Check if stats tables exist
        if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $stats_table)) != $stats_table) {
            return 0;
        }

        // Get stats for this link (batched for performance)
        // Process in chunks to avoid memory issues
        $batch_size = LinkCentral_ThirstyAffiliates_Utils::STATS_BATCH_SIZE;
        $offset = 0;
        $total_imported = 0;

        while (true) {
            // First get the click records
            $clicks = $wpdb->get_results($wpdb->prepare("
                SELECT id, date_clicked, link_id
                FROM `{$wpdb->prefix}ta_link_clicks`
                WHERE link_id = %d
                ORDER BY date_clicked ASC
                LIMIT %d OFFSET %d
            ", $ta_link_id, $batch_size, $offset), ARRAY_A);

            if (empty($clicks)) {
                break; // No more stats for this link
            }

            // Get meta data for all clicks in this batch efficiently
            $click_ids = wp_list_pluck($clicks, 'id');
            $meta_data = $this->get_clicks_meta_data($click_ids);

            // Combine clicks with their meta data
            $stats = array();
            foreach ($clicks as $click) {
                $click_id = $click['id'];
                $stats[] = array(
                    'click_id' => $click_id,
                    'click_date' => $click['date_clicked'],
                    'link_id' => $click['link_id'],
                    'referrer' => $meta_data[$click_id]['http_referrer'] ?? '',
                    'destination_url' => $meta_data[$click_id]['redirect_url'] ?? '',
                    // Store ThirstyAffiliates browser_device format directly in user_agent field
                    // Format: "Browser|OS|Device" (e.g., "Chrome|macOS|desktop")
                    // This is compatible with our own user agent parser which uses
                    // substring matching (strpos) to extract browser, OS, and device information
                    'user_agent' => $meta_data[$click_id]['browser_device'] ?? '',
                    'keyword' => $meta_data[$click_id]['keyword'] ?? ''
                );
            }

            $batch_imported = $this->import_stats_batch($stats, $lc_link_id);
            $total_imported += $batch_imported;
            $offset += $batch_size;

            // Safety check to prevent infinite loops
            if ($offset > LinkCentral_ThirstyAffiliates_Utils::MAX_CLICKS_PER_LINK) { // Max clicks per link
                break;
            }
        }

        return $total_imported;
    }

    /**
     * Get meta data for multiple clicks efficiently
     *
     * @param array $click_ids Array of click IDs
     * @return array Meta data indexed by click_id
     */
    private function get_clicks_meta_data($click_ids) {
        global $wpdb;

        if (empty($click_ids)) {
            return array();
        }

        $meta_rows = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT click_id, meta_key, meta_value FROM `{$wpdb->prefix}ta_link_clicks_meta` WHERE click_id IN (" . implode(',', array_fill(0, count($click_ids), '%d')) . ')',
                $click_ids
            ),
            ARRAY_A
        );

        // Organize meta data by click_id
        $meta_data = array();
        foreach ($meta_rows as $row) {
            $click_id = $row['click_id'];
            if (!isset($meta_data[$click_id])) {
                $meta_data[$click_id] = array();
            }
            $meta_data[$click_id][$row['meta_key']] = $row['meta_value'];
        }

        return $meta_data;
    }

    /**
     * Import a batch of stats for a link
     *
     * @param array $stats Array of stat data
     * @param int $lc_link_id LinkCentral link ID
     * @return int Number of stats imported in this batch
     */
    private function import_stats_batch($stats, $lc_link_id) {
        global $wpdb;

        if (empty($stats)) {
            return 0;
        }

        $imported_count = 0;

        foreach ($stats as $stat) {
            // Convert ThirstyAffiliates stat to LinkCentral format
            $result = $wpdb->query(
                $wpdb->prepare(
                    "INSERT INTO `{$wpdb->prefix}linkcentral_stats` (link_id, click_date, referring_url, user_agent, destination_url, country) VALUES (%d, %s, %s, %s, %s, %s)",
                    $lc_link_id,
                    $stat['click_date'],
                    $stat['referrer'] ?: '',
                    $stat['user_agent'] ?: '', // browser/device info from ThirstyAffiliates
                    $stat['destination_url'] ?: '', // destination URL from ThirstyAffiliates
                    '' // country - ThirstyAffiliates doesn't store this
                )
            );

            if ($result !== false) {
                $imported_count++;
            }
        }

        return $imported_count;
    }

    /**
     * Resolve the category slug that ThirstyAffiliates would show in the URL for a link.
     *
     * Priority mirrors ThirstyAffiliates' own logic:
     *  1. The value saved in _ta_category_slug post meta (manually chosen category for slug).
     *  2. The slug of the first term returned by get_the_terms() for the link's affiliate-link
     *     categories (the same fallback used by TA's Helper_Functions::get_default_category_slug).
     *
     * @param array $ta_link Link data array including 'ID' and 'ta_category_slug'.
     * @return string Category slug, or empty string if none can be determined.
     */
    private function get_ta_category_slug($ta_link) {
        if (!empty($ta_link['ta_category_slug'])) {
            return $ta_link['ta_category_slug'];
        }

        $terms = get_the_terms($ta_link['ID'], 'thirstylink-category');

        if (is_wp_error($terms) || empty($terms)) {
            return '';
        }

        $term = array_shift($terms);
        return $term->slug;
    }

    /**
     * Convert ThirstyAffiliates nofollow setting to LinkCentral format
     *
     * @param string $rel_tags ThirstyAffiliates rel tags
     * @param string $no_follow ThirstyAffiliates no follow setting
     * @return string LinkCentral nofollow setting
     */
    private function convert_ta_nofollow($rel_tags, $no_follow) {
        if ($no_follow === 'yes' || strpos($rel_tags, 'nofollow') !== false) {
            return 'yes';
        } elseif ($no_follow === 'no') {
            return 'no';
        }
        return 'default';
    }

    /**
     * Convert ThirstyAffiliates sponsored setting to LinkCentral format
     *
     * @param string $rel_tags ThirstyAffiliates rel tags
     * @return string LinkCentral sponsored setting
     */
    private function convert_ta_sponsored($rel_tags) {
        if (strpos($rel_tags, 'sponsored') !== false) {
            return 'yes';
        }
        return 'default';
    }

    /**
     * Convert ThirstyAffiliates parameter forwarding to LinkCentral format
     *
     * @param string $pass_query_str ThirstyAffiliates pass query string setting
     * @return string LinkCentral parameter forwarding setting
     */
    private function convert_ta_parameter_forwarding($pass_query_str) {
        if ($pass_query_str === 'yes') {
            return 'yes';
        } elseif ($pass_query_str === 'no') {
            return 'no';
        }
        return 'default';
    }

    /**
     * Convert ThirstyAffiliates redirect type to LinkCentral format
     *
     * @param string $redirect_type ThirstyAffiliates redirect type
     * @return string LinkCentral redirect type
     */
    private function convert_ta_redirect_type($redirect_type) {
        switch ($redirect_type) {
            case '301':
                return '301';
            case '302':
                return '302';
            case '307':
                return '307';
            default:
                return 'default';
        }
    }
}
