<?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\Package\Archive\PackageArchive;
use Duplicator\Utils\UsageStatistics\StatsUtil;

/**
 * Bridges ScheduleAddon into the ProBase telemetry pipeline.
 *
 * ProBase owns the "when" (the event firing) and defaults `execution_type`
 * to "manual"; this integration owns the "what" by upgrading the value to
 * "scheduled" or "run_now" when the package is tied to a schedule. Hooks
 * the `duplicator_telemetry_event_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'      => $frequency,
                'components'     => StatsUtil::getStatsComponents($components),
                'archive_format' => self::resolveArchiveFormat(),
                '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 format from the global setting — schedules don't
     * carry their own `archive_build_mode`; they inherit it at run time.
     *
     * @return string One of: dup, zip, shellzip, unknown
     */
    private static function resolveArchiveFormat(): string
    {
        switch ((int) GlobalEntity::getInstance()->archive_build_mode) {
            case PackageArchive::BUILD_MODE_DUP_ARCHIVE:
                return 'dup';
            case PackageArchive::BUILD_MODE_ZIP_ARCHIVE:
                return 'zip';
            case PackageArchive::BUILD_MODE_SHELL_EXEC:
                return 'shellzip';
            default:
                return 'unknown';
        }
    }

    /**
     * Override `execution_type` for backup_complete / backup_failed events
     * when the package belongs to a schedule. Other events are passed
     * through unchanged.
     *
     * @param array<string, mixed> $fields       Fields built by the originator
     * @param string               $eventType    Event discriminator
     * @param string               $_eventDetail Primary categorical dimension (unused, filter signature)
     * @param mixed                $context      Source object (AbstractPackage for backup_*)
     *
     * @return array<string, mixed>
     */
    public static function filterEventFields(array $fields, string $eventType, string $_eventDetail, $context): array
    {
        if ($eventType !== 'backup_complete' && $eventType !== 'backup_failed') {
            return $fields;
        }

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

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

        $fields['execution_type'] = self::resolveExecutionType($packageId);
        return $fields;
    }

    /**
     * @param int $packageId Package ID whose schedule relation is read
     *
     * @return string One of: manual, scheduled, run_now
     */
    private static function resolveExecutionType(int $packageId): string
    {
        switch (SchedulePackageRelation::getExecutionType($packageId)) {
            case SchedulePackageRelation::EXEC_TYPE_SCHEDULED:
                return 'scheduled';
            case SchedulePackageRelation::EXEC_TYPE_RUN_NOW:
                return 'run_now';
            default:
                return 'manual';
        }
    }
}
