<?php

namespace Fotogenic_AI;

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

final class Bulk_Scheduler {
    private static ?Bulk_Scheduler $instance = null;
    public const HOOK_TICK = 'fotogenic_ai_bulk_tick';
    public const GROUP = 'fotogenic_ai_bulk';

    private function __construct() {}

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

    public function has_action_scheduler(): bool {
		if ( ! function_exists( 'as_schedule_single_action' ) ) {
			return false;
		}
		if ( class_exists( '\\ActionScheduler' ) && method_exists( '\\ActionScheduler', 'is_initialized' ) ) {
			return (bool) \ActionScheduler::is_initialized();
		}
		return did_action( 'action_scheduler_init' ) > 0;
    }

    public function has_scheduled_tick( string $run_uuid, int $user_id ): bool {
        $run_uuid = trim( $run_uuid );
        if ( '' === $run_uuid || $user_id <= 0 || ! Background_Runtime_State::is_enabled() ) {
            return false;
        }
        $args = [ 'run_uuid' => $run_uuid, 'user_id' => $user_id ];
        if ( $this->has_action_scheduler() ) {
            if ( function_exists( 'as_get_scheduled_actions' ) ) {
                if ( $this->has_pending_action( $args ) ) {
                    return true;
                }
            }
            if ( function_exists( 'as_has_scheduled_action' ) ) {
                try {
                    if ( as_has_scheduled_action( self::HOOK_TICK, $args, self::GROUP ) ) {
                        return true;
                    }
                } catch ( \Throwable $error ) {
                    unset( $error );
					Logger::instance()->warn( 'bulk_scheduler_lookup_failed' );
                }
            }
        }
        return (bool) wp_next_scheduled( self::HOOK_TICK, [ $run_uuid, $user_id ] );
    }

    public function schedule_tick( string $run_uuid, int $user_id, int $delay_seconds ): bool {
        $run_uuid = trim( $run_uuid );
        if ( '' === $run_uuid || $user_id <= 0 || ! Background_Runtime_State::is_enabled() ) {
            return false;
        }
        $delay_seconds = max( 1, min( 300, $delay_seconds ) );
        $timestamp = time() + $delay_seconds;
        $args = [ 'run_uuid' => $run_uuid, 'user_id' => $user_id ];

        if ( $this->has_action_scheduler() ) {
            $supports_pending_query = function_exists( 'as_get_scheduled_actions' );
            if ( $supports_pending_query && $this->has_pending_action( $args ) ) {
                return $this->confirm_tick_schedule( $run_uuid, $user_id );
            }

            // AS uniqueness includes the action currently running, so it cannot create its successor.
            try {
                $action_id = as_schedule_single_action( $timestamp, self::HOOK_TICK, $args, self::GROUP, ! $supports_pending_query );
                if ( is_numeric( $action_id ) && $action_id > 0 ) {
                    return $this->confirm_tick_schedule( $run_uuid, $user_id );
                }
                if ( $supports_pending_query && $this->has_pending_action( $args ) ) {
                    return $this->confirm_tick_schedule( $run_uuid, $user_id );
                }
            } catch ( \Throwable $error ) {
                unset( $error );
				Logger::instance()->warn( 'bulk_scheduler_schedule_failed' );
            }
        }

        $cron_args = [ $run_uuid, $user_id ];
        wp_clear_scheduled_hook( self::HOOK_TICK, [ $args ] );
        if ( wp_next_scheduled( self::HOOK_TICK, $cron_args ) ) {
            return $this->confirm_tick_schedule( $run_uuid, $user_id );
        }
        $scheduled = wp_schedule_single_event( $timestamp, self::HOOK_TICK, $cron_args, true );
        if ( is_wp_error( $scheduled ) || false === $scheduled ) {
            return false;
        }
        return $this->confirm_tick_schedule( $run_uuid, $user_id );
    }

    public function deactivation_cleanup(): void {
        wp_unschedule_hook( self::HOOK_TICK );
		$this->deactivation_action_scheduler_cleanup();
    }

    public function deactivation_action_scheduler_cleanup(): void {
        if ( ! $this->has_action_scheduler() || ! function_exists( 'as_unschedule_all_actions' ) ) {
            return;
        }
        as_unschedule_all_actions( self::HOOK_TICK );
    }

    public function unschedule_tick( string $run_uuid, int $user_id ): void {
        $run_uuid = trim( $run_uuid );
        if ( '' === $run_uuid ) {
            return;
        }
        $args = [ 'run_uuid' => $run_uuid, 'user_id' => $user_id ];
        if ( $this->has_action_scheduler() && function_exists( 'as_unschedule_action' ) ) {
            try {
                as_unschedule_action( self::HOOK_TICK, $args, self::GROUP );
            } catch ( \Throwable $error ) {
                unset( $error );
				Logger::instance()->warn( 'bulk_scheduler_unschedule_failed' );
            }
        }
        wp_clear_scheduled_hook( self::HOOK_TICK, [ $run_uuid, $user_id ] );
        wp_clear_scheduled_hook( self::HOOK_TICK, [ $args ] );
    }

    private function confirm_tick_schedule( string $run_uuid, int $user_id ): bool {
        if ( Background_Runtime_State::is_enabled() ) {
            return true;
        }
        $this->unschedule_tick( $run_uuid, $user_id );
        return false;
    }

    private function has_pending_action( array $args ): bool {
        if ( ! function_exists( 'as_get_scheduled_actions' ) ) {
            return false;
        }

        try {
            $action_ids = as_get_scheduled_actions(
                [
                    'hook'     => self::HOOK_TICK,
                    'args'     => $args,
                    'group'    => self::GROUP,
                    'status'   => 'pending',
                    'per_page' => 1,
                ],
                'ids'
            );
        } catch ( \Throwable $error ) {
            unset( $error );
			Logger::instance()->warn( 'bulk_scheduler_pending_lookup_failed' );
            return false;
        }
        return ! empty( $action_ids );
    }
}
