<?php
/**
 * Scheduled catalogue sync to Askagento (plan cadence: free monthly, basic/pro daily).
 */

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

if (!defined('ASKAGENTO_CATALOGUE_SYNC_CRON_HOOK')) {
    define('ASKAGENTO_CATALOGUE_SYNC_CRON_HOOK', 'askagento_catalogue_sync_cron_event');
}

if (!defined('ASKAGENTO_OPTION_CATALOGUE_SYNC_LAST_SLOT')) {
    define('ASKAGENTO_OPTION_CATALOGUE_SYNC_LAST_SLOT', 'askagento_catalogue_auto_sync_last_slot');
}

if (!defined('ASKAGENTO_OPTION_CATALOGUE_SYNC_LAST_RUN')) {
    define('ASKAGENTO_OPTION_CATALOGUE_SYNC_LAST_RUN', 'askagento_catalogue_auto_sync_last_run');
}

if (!defined('ASKAGENTO_OPTION_CATALOGUE_SYNC_LAST_ERROR')) {
    define('ASKAGENTO_OPTION_CATALOGUE_SYNC_LAST_ERROR', 'askagento_catalogue_auto_sync_last_error');
}

/**
 * Whether the shop finished Askagento registration (site id + API key, consent cleared).
 *
 * @return bool
 */
function askagento_catalogue_sync_is_registered() {
    if (get_option('askagento_consent_required')) {
        return false;
    }

    $site_id = trim((string) get_option('askagento_install_site_id', ''));
    if ($site_id === '' || !function_exists('askagento_get_install_settings')) {
        return false;
    }

    $settings = askagento_get_install_settings();
    $api_key  = isset($settings['api_key']) ? trim((string) $settings['api_key']) : '';

    return $api_key !== '' && askagento_install_api_is_enabled();
}

/**
 * @return DateTimeImmutable|null Last fulfilled catalogue slot (UTC).
 */
function askagento_catalogue_sync_get_last_fulfilled_slot() {
    $raw = trim((string) get_option(ASKAGENTO_OPTION_CATALOGUE_SYNC_LAST_SLOT, ''));

    return $raw !== '' ? askagento_parse_installed_at_utc($raw) : null;
}

/**
 * Record the catalogue update slot fulfilled by the latest sync.
 *
 * @param DateTimeImmutable|string|null $slot UTC slot; defaults to now.
 */
function askagento_catalogue_sync_mark_slot_fulfilled($slot = null) {
    if ($slot instanceof DateTimeImmutable) {
        $stored = $slot->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d\TH:i:s\Z');
    } elseif (is_string($slot) && trim($slot) !== '') {
        $dt = askagento_parse_installed_at_utc($slot);
        $stored = $dt ? $dt->format('Y-m-d\TH:i:s\Z') : trim($slot);
    } else {
        $stored = gmdate('Y-m-d\TH:i:s\Z');
    }

    update_option(ASKAGENTO_OPTION_CATALOGUE_SYNC_LAST_SLOT, $stored, false);
    delete_option(ASKAGENTO_OPTION_CATALOGUE_SYNC_LAST_ERROR);
}

/**
 * Mark successful sync (manual, install, or cron) and optional run metadata.
 *
 * @param DateTimeImmutable|string|null $slot
 * @param array<string, mixed>          $run_meta
 */
function askagento_catalogue_sync_record_success($slot = null, array $run_meta = []) {
    askagento_catalogue_sync_mark_slot_fulfilled($slot);

    $meta = array_merge(
        [
            'time' => current_time('mysql'),
        ],
        $run_meta
    );
    update_option(ASKAGENTO_OPTION_CATALOGUE_SYNC_LAST_RUN, wp_json_encode($meta), false);
}

/**
 * @param string $message
 * @param array<string, mixed> $extra
 */
function askagento_catalogue_sync_record_error($message, array $extra = []) {
    update_option(
        ASKAGENTO_OPTION_CATALOGUE_SYNC_LAST_ERROR,
        wp_json_encode(
            array_merge(
                [
                    'time'    => current_time('mysql'),
                    'message' => $message,
                ],
                $extra
            ),
            JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
        ),
        false
    );
}

/**
 * Plan slug and install anchor for cadence checks.
 *
 * @return array{site_id: string, plan_slug: string, installed_at: string}|WP_Error
 */
function askagento_catalogue_sync_resolve_schedule_context() {
    $site_id = trim((string) get_option('askagento_install_site_id', ''));
    if ($site_id === '') {
        return new WP_Error('no_site', __('No installation ID found', 'askagento'));
    }

    $status = askagento_check_install_status($site_id);
    if (is_wp_error($status)) {
        return $status;
    }

    $installed_at = isset($status['installed_at']) ? trim((string) $status['installed_at']) : '';
    if ($installed_at === '') {
        return new WP_Error(
            'no_installed_at',
            __('Install status API returned no installation date.', 'askagento')
        );
    }

    $plan_slug = 'free';
    $plan_res  = askagento_fetch_plan($site_id);
    if (is_wp_error($plan_res)) {
        return $plan_res;
    }
    if (is_array($plan_res) && !empty($plan_res['plan'])) {
        $plan_slug = (string) $plan_res['plan'];
    }

    return [
        'site_id'      => $site_id,
        'plan_slug'    => $plan_slug,
        'installed_at' => $installed_at,
    ];
}

/**
 * Run scheduled catalogue sync when due for the site's plan.
 *
 * @param string $context Optional slug for logging (cron, upgrade).
 */
function askagento_catalogue_sync_run_scheduled($context = 'cron') {
    unset($context);

    if (!askagento_catalogue_sync_is_registered()) {
        return;
    }

    if (!function_exists('askagento_sync_product_data_to_api')) {
        return;
    }

    $ctx = askagento_catalogue_sync_resolve_schedule_context();
    if (is_wp_error($ctx)) {
        askagento_catalogue_sync_record_error($ctx->get_error_message(), ['code' => $ctx->get_error_code()]);
        return;
    }

    $last_slot = askagento_catalogue_sync_get_last_fulfilled_slot();
    if (!askagento_catalogue_sync_is_due_for_plan($ctx['installed_at'], $ctx['plan_slug'], $last_slot)) {
        return;
    }

    $due_slot = askagento_get_last_update_due_before_now($ctx['installed_at'], $ctx['plan_slug']);
    if ($due_slot === null) {
        return;
    }

    $result = askagento_sync_product_data_to_api();
    if (is_wp_error($result)) {
        askagento_catalogue_sync_record_error(
            $result->get_error_message(),
            ['code' => $result->get_error_code()]
        );
        return;
    }

    askagento_catalogue_sync_record_success(
        $due_slot,
        [
            'synced_products' => (int) ($result['synced_products'] ?? 0),
            'plan_slug'       => $ctx['plan_slug'],
            'trigger'         => 'auto',
        ]
    );
}

/**
 * Schedule daily WP-Cron hook (checks plan cadence inside the handler).
 */
function askagento_catalogue_sync_schedule_cron() {
    if (wp_next_scheduled(ASKAGENTO_CATALOGUE_SYNC_CRON_HOOK)) {
        return;
    }
    wp_schedule_event(time() + 300, 'daily', ASKAGENTO_CATALOGUE_SYNC_CRON_HOOK);
}

/**
 * Clear scheduled catalogue sync.
 */
function askagento_catalogue_sync_unschedule_cron() {
    wp_clear_scheduled_hook(ASKAGENTO_CATALOGUE_SYNC_CRON_HOOK);
}

/**
 * Ensure cron exists after registration / plugin upgrades.
 */
function askagento_catalogue_sync_maybe_schedule_cron() {
    if (!askagento_catalogue_sync_is_registered()) {
        return;
    }
    askagento_catalogue_sync_schedule_cron();
}

add_action(ASKAGENTO_CATALOGUE_SYNC_CRON_HOOK, static function () {
    askagento_catalogue_sync_run_scheduled('cron');
});

add_action(
    'plugins_loaded',
    static function () {
        askagento_catalogue_sync_maybe_schedule_cron();
    },
    20
);

add_action(
    'upgrader_process_complete',
    static function ($_upgrader, $options) {
        unset($_upgrader);
        if (empty($options['type']) || 'plugin' !== $options['type'] || empty($options['action']) || 'update' !== $options['action']) {
            return;
        }

        $slugs = [];
        if (!empty($options['plugins']) && is_array($options['plugins'])) {
            $slugs = $options['plugins'];
        }
        if (!empty($options['plugin']) && is_string($options['plugin'])) {
            $slugs[] = $options['plugin'];
        }

        $basename = plugin_basename(ASKAGENTO_PLUGIN_FILE);
        foreach ($slugs as $slug) {
            if ($slug === $basename) {
                askagento_catalogue_sync_maybe_schedule_cron();
                break;
            }
        }
    },
    10,
    2
);
