<?php
if (!defined('ABSPATH')) exit;

/**
 * Main orchestrator that wires up Admin, Metabox, Frontend, and API.
 */
class SAA_Plugin {

    /** @var array */
    private $options = [];

    /** @var SAA_Admin|null */
    private $admin = null;

    /** @var SAA_Metabox|null */
    private $metabox = null;

    /** @var SAA_Frontend|null */
    private $frontend = null;

    /** @var SAA_API|null */
    private $api = null;

    public function __construct() {
        // Load saved options safely (array-only)
        $opts = get_option('saa_options', []);
        $this->options = is_array($opts) ? $opts : [];

        // Ensure expected keys exist
        $this->options = wp_parse_args($this->options, [
            'associate_tag'        => '',
            'access_key'           => '',
            'secret_key'           => '',
            'region'               => '', // '', UK, US, CA, DE, FR, IT, ES, JP, IN
            'delete_on_uninstall'  => 0,
        ]);
    }

    /**
     * Entry point: register components and hooks.
     */
    public function run() {
        // Always load API wrapper (used by admin + metabox + cron)
        if (class_exists('SAA_API')) {
            $this->api = new SAA_API($this);
        }

        // Frontend (shortcode + rendering)
        if (class_exists('SAA_Frontend')) {
            $this->frontend = new SAA_Frontend($this);
            $this->frontend->init();
        }

        // Admin UI + Settings
        if (is_admin() && current_user_can('manage_options') && class_exists('SAA_Admin')) {
            $this->admin = new SAA_Admin($this);
            $this->admin->init();
        }

        // Metabox (admin-only access as specified)
        if (is_admin() && current_user_can('manage_options') && class_exists('SAA_Metabox')) {
            $this->metabox = new SAA_Metabox($this);
            $this->metabox->init();
        }

        // Cron: weekly price refresh (only if API is configured)
        add_action('init', [$this, 'maybe_schedule_price_refresh']);
        add_action('saa_weekly_price_refresh', [$this, 'handle_weekly_price_refresh']);
    }

    /**
     * Public accessor for options (read-only array).
     */
    public function get_options(): array {
        return $this->options;
    }

    /**
     * Get a single option with a default.
     */
    public function get_option(string $key, $default = '') {
        return $this->options[$key] ?? $default;
    }

    /**
     * Update options safely and keep in-memory copy in sync.
     */
    public function update_options(array $new): bool {
        $merged = wp_parse_args($new, $this->options);
        $ok = update_option('saa_options', $merged, true);
        if ($ok) {
            $this->options = $merged;
        }
        return (bool) $ok;
    }

    /**
     * Return API instance (may be null if class unavailable).
     */
    public function api(): ?SAA_API {
        return $this->api;
    }

    /**
     * Whether API credentials appear complete.
     */
    public function is_api_configured(): bool {
        return !empty($this->options['associate_tag'])
            && !empty($this->options['access_key'])
            && !empty($this->options['secret_key'])
            && !empty($this->options['region']);
    }

    /**
     * Human-readable domain label by region code (for settings UI/validation).
     */
    public function region_to_domain(string $region): string {
        $map = [
            ''    => '',
            'UK'  => 'amazon.co.uk',
            'US'  => 'amazon.com',
            'CA'  => 'amazon.ca',
            'DE'  => 'amazon.de',
            'FR'  => 'amazon.fr',
            'IT'  => 'amazon.it',
            'ES'  => 'amazon.es',
            'JP'  => 'amazon.co.jp',
            'IN'  => 'amazon.in',
        ];
        return $map[$region] ?? '';
    }

    /**
     * Schedule weekly refresh if API is configured.
     */
    public function maybe_schedule_price_refresh(): void {
        if ($this->is_api_configured() && !wp_next_scheduled('saa_weekly_price_refresh')) {
            // Schedule for next 3am site time, weekly.
            $first = strtotime('tomorrow 3am');
            wp_schedule_event($first, 'weekly', 'saa_weekly_price_refresh');
        }

        // If API becomes unconfigured, unschedule existing job.
        if (!$this->is_api_configured()) {
            $ts = wp_next_scheduled('saa_weekly_price_refresh');
            if ($ts) {
                wp_unschedule_event($ts, 'saa_weekly_price_refresh');
            }
        }
    }

    /**
     * Cron callback: delegate to API class to refresh cached prices.
     */
    public function handle_weekly_price_refresh(): void {
        if (!$this->is_api_configured() || !$this->api) {
            return;
        }
        // Let API class decide how/what to refresh.
        if (method_exists($this->api, 'refresh_cached_prices')) {
            try {
                $this->api->refresh_cached_prices();
            } catch (\Throwable $e) {
                // Fail silently to avoid breaking cron; log for admins.
                error_log('[SAA] Weekly price refresh failed: ' . $e->getMessage());
            }
        }
    }

    /**
     * Build a sanitized affiliate URL. If a raw Amazon URL is provided,
     * append tag if missing; otherwise return as-is (for non-Amazon affiliates).
     * This is a helper used by the frontend renderer.
     */
    public function build_affiliate_url(string $url): string {
        $url = trim($url);
        if ($url === '') return '';

        $parsed = wp_parse_url($url);
        if (empty($parsed['host'])) {
            return esc_url_raw($url);
        }

        // Only attempt to add tag for Amazon domains.
        if (strpos($parsed['host'], 'amazon.') !== false && !empty($this->options['associate_tag'])) {
            // If tag already present, keep it
            if (strpos($url, 'tag=') === false) {
                $sep = (strpos($url, '?') === false) ? '?' : '&';
                $url .= $sep . 'tag=' . rawurlencode($this->options['associate_tag']);
            }
        }

        return esc_url_raw($url);
    }
}
