<?php

/**
 * Campaign Manager
 * 
 * Manages newsletter campaign CRUD operations and sending
 * 
 * @package WooNooW\Core\Campaigns
 */

namespace WooNooW\Core\Campaigns;

use WooNooW\Database\SubscriberTable;

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

class CampaignManager
{

    const POST_TYPE = 'wnw_campaign';
    const CRON_HOOK = 'woonoow_process_scheduled_campaigns';

    private static $instance = null;

    /**
     * Get instance
     */
    public static function instance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Initialize
     */
    public static function init()
    {
        add_action('init', [__CLASS__, 'register_post_type']);
        add_action(self::CRON_HOOK, [__CLASS__, 'process_scheduled_campaigns']);
    }

    /**
     * Register campaign post type
     */
    public static function register_post_type()
    {
        register_post_type(self::POST_TYPE, [
            'labels' => [
                'name' => __('Campaigns', 'woonoow'),
                'singular_name' => __('Campaign', 'woonoow'),
            ],
            'public' => false,
            'show_ui' => false,
            'show_in_rest' => false,
            'supports' => ['title'],
            'capability_type' => 'post',
            'map_meta_cap' => true,
        ]);
    }

    /**
     * Create a new campaign
     * 
     * @param array $data Campaign data
     * @return int|WP_Error Campaign ID or error
     */
    public static function create($data)
    {
        $post_data = [
            'post_type' => self::POST_TYPE,
            'post_status' => 'publish',
            'post_title' => sanitize_text_field($data['title'] ?? 'Untitled Campaign'),
        ];

        $campaign_id = wp_insert_post($post_data, true);

        if (is_wp_error($campaign_id)) {
            return $campaign_id;
        }

        // Save meta fields
        self::update_meta($campaign_id, $data);

        return $campaign_id;
    }

    /**
     * Update campaign
     * 
     * @param int $campaign_id Campaign ID
     * @param array $data Campaign data
     * @return bool|WP_Error
     */
    public static function update($campaign_id, $data)
    {
        $post = get_post($campaign_id);

        if (!$post || $post->post_type !== self::POST_TYPE) {
            return new \WP_Error('invalid_campaign', __('Campaign not found', 'woonoow'));
        }

        // Update title if provided
        if (isset($data['title'])) {
            wp_update_post([
                'ID' => $campaign_id,
                'post_title' => sanitize_text_field($data['title']),
            ]);
        }

        // Update meta fields
        self::update_meta($campaign_id, $data);

        return true;
    }

    /**
     * Update campaign meta
     * 
     * @param int $campaign_id
     * @param array $data
     */
    private static function update_meta($campaign_id, $data)
    {
        $meta_fields = [
            'subject' => '_wnw_subject',
            'content' => '_wnw_content',
            'status' => '_wnw_status',
            'scheduled_at' => '_wnw_scheduled_at',
        ];

        foreach ($meta_fields as $key => $meta_key) {
            if (isset($data[$key])) {
                $value = $data[$key];

                // Sanitize based on field type
                if ($key === 'content') {
                    $value = wp_kses_post($value);
                } elseif ($key === 'scheduled_at') {
                    $value = sanitize_text_field($value);
                } elseif ($key === 'status') {
                    $allowed = ['draft', 'scheduled', 'sending', 'sent', 'failed'];
                    $value = in_array($value, $allowed) ? $value : 'draft';
                } else {
                    $value = sanitize_text_field($value);
                }

                update_post_meta($campaign_id, $meta_key, $value);
            }
        }

        // Set default status if not provided
        if (!get_post_meta($campaign_id, '_wnw_status', true)) {
            update_post_meta($campaign_id, '_wnw_status', 'draft');
        }
    }

    /**
     * Get campaign by ID
     * 
     * @param int $campaign_id
     * @return array|null
     */
    public static function get($campaign_id)
    {
        $post = get_post($campaign_id);

        if (!$post || $post->post_type !== self::POST_TYPE) {
            return null;
        }

        return self::format_campaign($post);
    }

    /**
     * Get all campaigns
     * 
     * @param array $args Query args
     * @return array
     */
    public static function get_all($args = [])
    {
        $defaults = [
            'post_type' => self::POST_TYPE,
            'post_status' => 'any',
            'posts_per_page' => -1,
            'orderby' => 'date',
            'order' => 'DESC',
        ];

        $query_args = wp_parse_args($args, $defaults);
        $query_args['post_type'] = self::POST_TYPE; // Force post type

        $posts = get_posts($query_args);

        return array_map([__CLASS__, 'format_campaign'], $posts);
    }

    /**
     * Format campaign post to array
     * 
     * @param WP_Post $post
     * @return array
     */
    private static function format_campaign($post)
    {
        return [
            'id' => $post->ID,
            'title' => $post->post_title,
            'subject' => get_post_meta($post->ID, '_wnw_subject', true),
            'content' => get_post_meta($post->ID, '_wnw_content', true),
            'status' => get_post_meta($post->ID, '_wnw_status', true) ?: 'draft',
            'scheduled_at' => get_post_meta($post->ID, '_wnw_scheduled_at', true),
            'sent_at' => get_post_meta($post->ID, '_wnw_sent_at', true),
            'recipient_count' => (int) get_post_meta($post->ID, '_wnw_recipient_count', true),
            'sent_count' => (int) get_post_meta($post->ID, '_wnw_sent_count', true),
            'failed_count' => (int) get_post_meta($post->ID, '_wnw_failed_count', true),
            'created_at' => $post->post_date,
            'updated_at' => $post->post_modified,
        ];
    }

    /**
     * Delete campaign
     * 
     * @param int $campaign_id
     * @return bool
     */
    public static function delete($campaign_id)
    {
        $post = get_post($campaign_id);

        if (!$post || $post->post_type !== self::POST_TYPE) {
            return false;
        }

        return wp_delete_post($campaign_id, true) !== false;
    }

    /**
     * Send campaign
     * 
     * @param int $campaign_id
     * @return array Result with sent/failed counts
     */
    public static function send($campaign_id)
    {
        $campaign = self::get($campaign_id);

        if (!$campaign) {
            return ['success' => false, 'error' => __('Campaign not found', 'woonoow')];
        }

        if ($campaign['status'] === 'sent') {
            return ['success' => false, 'error' => __('Campaign already sent', 'woonoow')];
        }

        // Get subscribers
        $subscribers = self::get_subscribers();

        if (empty($subscribers)) {
            return ['success' => false, 'error' => __('No subscribers to send to', 'woonoow')];
        }

        // Update status to sending
        update_post_meta($campaign_id, '_wnw_status', 'sending');
        update_post_meta($campaign_id, '_wnw_recipient_count', count($subscribers));

        $sent = 0;
        $failed = 0;

        // Get email template
        $template = self::render_campaign_email($campaign);

        // Send in batches
        $batch_size = 50;
        $batches = array_chunk($subscribers, $batch_size);

        foreach ($batches as $batch) {
            foreach ($batch as $subscriber) {
                $email = $subscriber['email'];

                // Replace subscriber-specific variables
                $body = str_replace('{subscriber_email}', $email, $template['body']);
                $body = str_replace('{unsubscribe_url}', self::get_unsubscribe_url($email), $body);

                // Send email
                $result = wp_mail(
                    $email,
                    $template['subject'],
                    $body,
                    ['Content-Type: text/html; charset=UTF-8']
                );

                if ($result) {
                    $sent++;
                } else {
                    $failed++;
                }
            }

            // Small delay between batches
            if (count($batches) > 1) {
                sleep(2);
            }
        }

        // Update campaign stats
        update_post_meta($campaign_id, '_wnw_sent_count', $sent);
        update_post_meta($campaign_id, '_wnw_failed_count', $failed);
        update_post_meta($campaign_id, '_wnw_sent_at', current_time('mysql'));
        update_post_meta($campaign_id, '_wnw_status', $failed > 0 && $sent === 0 ? 'failed' : 'sent');

        return [
            'success' => true,
            'sent' => $sent,
            'failed' => $failed,
            'total' => count($subscribers),
        ];
    }

    /**
     * Send test email
     * 
     * @param int $campaign_id
     * @param string $email Test email address
     * @return bool
     */
    public static function send_test($campaign_id, $email)
    {
        $campaign = self::get($campaign_id);

        if (!$campaign) {
            return false;
        }

        $template = self::render_campaign_email($campaign);

        // Replace subscriber-specific variables
        $body = str_replace('{subscriber_email}', $email, $template['body']);
        $body = str_replace('{unsubscribe_url}', '#', $body);

        return wp_mail(
            $email,
            '[TEST] ' . $template['subject'],
            $body,
            ['Content-Type: text/html; charset=UTF-8']
        );
    }

    /**
     * Render campaign email using EmailRenderer
     * 
     * @param array $campaign
     * @return array ['subject' => string, 'body' => string]
     */
    private static function render_campaign_email($campaign)
    {
        $renderer = \WooNooW\Core\Notifications\EmailRenderer::instance();

        // Get the campaign email template
        $template = $renderer->get_template_settings('newsletter_campaign', 'customer');

        // Fallback if no template configured
        if (!$template) {
            $subject = $campaign['subject'] ?: $campaign['title'];
            $body = $campaign['content'];
        } else {
            $subject = $template['subject'] ?: $campaign['subject'];

            // Replace {content} with campaign content
            $body = str_replace('{content}', $campaign['content'], $template['body']);

            // Replace {campaign_title}
            $body = str_replace('{campaign_title}', $campaign['title'], $body);
        }

        // Replace common variables
        $site_name = get_bloginfo('name');
        $site_url = home_url();

        // Replace campaign-specific variables in subject
        $subject = str_replace('{campaign_title}', $campaign['title'], $subject);
        $subject = str_replace(['{site_name}', '{store_name}'], $site_name, $subject);
        $body = str_replace(['{site_name}', '{store_name}'], $site_name, $body);
        $body = str_replace('{site_url}', $site_url, $body);
        $body = str_replace('{current_date}', date_i18n(get_option('date_format')), $body);
        $body = str_replace('{current_year}', date('Y'), $body);

        // Parse card shortcodes before rendering
        $body = $renderer->parse_cards($body);

        // Render through email design template
        $design_path = $renderer->get_design_template();
        if (file_exists($design_path)) {
            $body = $renderer->render_html($design_path, $body, $subject, [
                'site_name' => $site_name,
                'site_url' => $site_url,
            ]);
        }

        return [
            'subject' => $subject,
            'body' => $body,
        ];
    }

    /**
     * Get subscribers
     * 
     * @param array $filters Optional audience filters
     * @return array
     */
    private static function get_subscribers($filters = [])
    {
        // Use SubscriberTable if available
        if (SubscriberTable::table_exists()) {
            return SubscriberTable::get_active($filters);
        }

        // Legacy: use wp_options storage
        $subscribers = get_option('woonoow_newsletter_subscribers', []);
        return array_filter($subscribers, function ($sub) {
            return ($sub['status'] ?? 'active') === 'active';
        });
    }

    /**
     * Check if subscribers table exists (deprecated - use SubscriberTable::table_exists())
     * 
     * @deprecated Use SubscriberTable::table_exists() instead
     * @return bool
     */
    private static function has_subscribers_table()
    {
        return SubscriberTable::table_exists();
    }

    /**
     * Get unsubscribe URL
     * 
     * @param string $email
     * @return string
     */
    private static function get_unsubscribe_url($email)
    {
        // Use NewsletterController's secure token-based URL
        return \WooNooW\API\NewsletterController::generate_unsubscribe_url($email);
    }

    /**
     * Process scheduled campaigns (WP-Cron)
     */
    public static function process_scheduled_campaigns()
    {
        // Only if scheduling is enabled
        if (!get_option('woonoow_campaign_scheduling_enabled', false)) {
            return;
        }

        $campaigns = self::get_all([
            'meta_query' => [
                [
                    'key' => '_wnw_status',
                    'value' => 'scheduled',
                ],
                [
                    'key' => '_wnw_scheduled_at',
                    'value' => current_time('mysql'),
                    'compare' => '<=',
                    'type' => 'DATETIME',
                ],
            ],
        ]);

        foreach ($campaigns as $campaign) {
            self::send($campaign['id']);
        }
    }

    /**
     * Enable scheduling (registers cron)
     */
    public static function enable_scheduling()
    {
        if (!wp_next_scheduled(self::CRON_HOOK)) {
            wp_schedule_event(time(), 'hourly', self::CRON_HOOK);
        }
    }

    /**
     * Disable scheduling (clears cron)
     */
    public static function disable_scheduling()
    {
        wp_clear_scheduled_hook(self::CRON_HOOK);
    }
}
