<?php

declare(strict_types=1);

namespace Duplicator\Addons\ScheduleAddon;

use Duplicator\Addons\ProBase\Telemetry\TelemetryEvents;
use Duplicator\Addons\ScheduleAddon\Models\ScheduleEntity;
use Duplicator\Addons\ScheduleAddon\Models\SchedulePackageRelation;
use Duplicator\Models\GlobalEntity;
use Duplicator\Package\AbstractPackage;
use Duplicator\Utils\UsageStatistics\StatsUtil;

/**
 * Bridges ScheduleAddon into the ProBase telemetry pipeline.
 *
 * ProBase fires backup_build events with a default execution_type field;
 * this integration overrides it when the package is tied to a schedule, via
 * the telemetry fields filter so probase has zero compile-time dependency
 * on ScheduleAddon.
 */
class ScheduleTelemetryIntegration
{
    /**
     * Register filter hooks. Called from ScheduleAddon::init().
     *
     * @return void
     */
    public static function register(): void
    {
        add_filter('duplicator_telemetry_event_fields', [self::class, 'filterEventFields'], 10, 4);
        add_action('duplicator_after_schedule_create', [self::class, 'onScheduleCreated'], 100, 1);
    }

    /**
     * Emit `schedule_created` when a new schedule entity is persisted. The
     * event is owned by ScheduleAddon (not probase) because the schedule
     * concept is addon-scoped — probase has no compile-time view of it.
     *
     * @param ScheduleEntity $schedule Newly created schedule
     *
     * @return void
     */
    public static function onScheduleCreated(ScheduleEntity $schedule): void
    {
        $frequency  = self::resolveFrequency($schedule->repeat_type);
        $template   = $schedule->getTemplate();
        $components = ($template !== false) ? $template->components : [];

        TelemetryEvents::track(
            'schedule',
            'created',
            [
                'frequency'      => $frequency,
                'components'     => StatsUtil::getStatsComponents($components),
                'archive_engine' => self::resolveArchiveEngine(),
                'storage_count'  => count($schedule->storage_ids),
            ],
            $schedule
        );
    }

    /**
     * Map the integer `repeat_type` to the stable English label expected by
     * the worker. Localized labels would break worker-side `GROUP BY` so we
     * never call `getRepeatText()`.
     *
     * @param int $repeatType ScheduleEntity::REPEAT_* enum
     *
     * @return string
     */
    private static function resolveFrequency(int $repeatType): string
    {
        switch ($repeatType) {
            case ScheduleEntity::REPEAT_HOURLY:
                return 'hourly';
            case ScheduleEntity::REPEAT_DAILY:
                return 'daily';
            case ScheduleEntity::REPEAT_WEEKLY:
                return 'weekly';
            case ScheduleEntity::REPEAT_MONTHLY:
                return 'monthly';
            default:
                return 'unknown';
        }
    }

    /**
     * Resolve the archive engine from the global setting — schedules don't
     * carry their own `archive_build_mode` / `ziparchive_mode`; they inherit
     * both at run time, so the global is the value the build will use.
     *
     * @return string
     */
    private static function resolveArchiveEngine(): string
    {
        $global = GlobalEntity::getInstance();
        return TelemetryEvents::archiveEngineName($global->getBuildMode(), (int) $global->ziparchive_mode);
    }

    /**
     * Override the `execution_type` field on backup_build events when the
     * package belongs to a schedule. Other events and fields are passed
     * through unchanged.
     *
     * @param array<string, mixed> $fields       Fields built by the originator
     * @param string               $eventType    Event family
     * @param string               $eventSubType Outcome within the family
     * @param mixed                $context      Source object (AbstractPackage for backup_build)
     *
     * @return array<string, mixed>
     */
    public static function filterEventFields(array $fields, string $eventType, string $eventSubType, $context): array
    {
        if ($eventType !== 'backup_build') {
            return $fields;
        }

        if (!$context instanceof AbstractPackage) {
            return $fields;
        }

        $packageId = $context->getId();
        if ($packageId <= 0) {
            return $fields;
        }

        // Only packages with a schedule relation are overridden, the
        // originator value is kept for everything else.
        switch (SchedulePackageRelation::getExecutionType($packageId)) {
            case SchedulePackageRelation::EXEC_TYPE_SCHEDULED:
                $fields['execution_type'] = 'scheduled';
                break;
            case SchedulePackageRelation::EXEC_TYPE_RUN_NOW:
                $fields['execution_type'] = 'run_now';
                break;
        }

        return $fields;
    }
}
