#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

// Extension-event vocabulary for plugin packages that emit feature
// telemetry (ads). Pure C, safe in this ObjC-only header.
#import "aviation_extension_events.h"

NS_ASSUME_NONNULL_BEGIN

typedef void (^AviationVoidBlock)(void);

/**
 * Command vocabulary a guard may suppress. This is the public contract for
 * plugin packages; the values are checked against the internal C enum in
 * AviationEngineRegistry.m, so drift is a compile error rather than a
 * silently misrouted guard.
 */
typedef NS_ENUM(uint32_t, AviationGuardedCommand) {
    AviationGuardedCommandLoad = 0,
    AviationGuardedCommandPlay = 1,
    AviationGuardedCommandPause = 2,
    AviationGuardedCommandSeek = 3,
    AviationGuardedCommandStop = 4,
};

typedef BOOL (^AviationCommandGuardBlock)(uint32_t commandType);
typedef uint32_t (^AviationDomainEventSubscribeBlock)(void (^callback)(int32_t type, int32_t queueIndex));
typedef void (^AviationDomainEventUnsubscribeBlock)(uint32_t subscriptionId);
typedef void (^AviationStateChangeUnsubscribeBlock)(void);
typedef AviationStateChangeUnsubscribeBlock _Nullable (^AviationStateChangeSubscribeBlock)(void (^callback)(int32_t state));
typedef void (^AviationSetAdModeBlock)(NSString *title, double durationSeconds);
typedef void (^AviationEmitAdDomainEventBlock)(int32_t type,
    int32_t breakIndex, double breakTimeMs, int32_t totalAdsInBreak,
    NSString *_Nullable adId, NSString *_Nullable title,
    double durationMs, double currentMs,
    int32_t adIndexInBreak, int32_t adTotalAdsInBreak,
    BOOL isSkippable, double skipOffsetMs,
    NSString *_Nullable errorMessage);
typedef void (^AviationInstallCommandGuardBlock)(NSObject *owner, AviationCommandGuardBlock block);
typedef void (^AviationClearCommandGuardBlock)(NSObject *owner);

// ---------------------------------------------------------------------------
// Playback output
// ---------------------------------------------------------------------------

/**
 * An output that owns playback instead of the local decoder — a Cast receiver,
 * say. While one is installed the engine redirects its decoder commands here.
 *
 * ObjC rather than the Swift PlaybackOutputPort because plugin pods cannot
 * import the Aviation Swift module (its umbrella header includes C++ headers).
 * Core adapts this to the Swift port internally, so the hexagonal port stays
 * the Swift one and this is purely the crossing.
 */
@protocol AviationPlaybackOutput <NSObject>

/// `metadata` carries the optional title/artist/album/artworkUri/mimeType keys.
- (void)outputLoadWithUri:(NSString *)uri
                 metadata:(NSDictionary<NSString *, NSString *> *)metadata
          startPositionMs:(double)startPositionMs;
- (void)outputPlay;
- (void)outputPause;
- (void)outputSeekTo:(double)positionMs;
- (void)outputStop;
- (void)outputSetRate:(double)rate;
- (void)outputSetVolume:(double)volume;
- (void)outputSetMuted:(BOOL)muted;

@end

/**
 * State vocabulary an output may report. Public contract for plugin packages;
 * the values are asserted against the internal C enum in
 * AviationEngineRegistry.m, so drift is a compile error rather than a silently
 * misreported state.
 */
typedef NS_ENUM(int32_t, AviationOutputState) {
    AviationOutputStateIdle = 0,
    AviationOutputStateLoading = 1,
    AviationOutputStateReady = 2,
    AviationOutputStateBuffering = 3,
    AviationOutputStateEnded = 4,
    AviationOutputStateError = 5,
    AviationOutputStatePaused = 6,
    AviationOutputStatePlaying = 7,
};

typedef void (^AviationInstallPlaybackOutputBlock)(NSObject *owner, id<AviationPlaybackOutput> output);
typedef void (^AviationClearPlaybackOutputBlock)(NSObject *owner);
typedef void (^AviationReportOutputTimeBlock)(double currentMs, double durationMs,
    double seekableStartMs, double seekableEndMs, BOOL isLive);
typedef void (^AviationReportOutputStateBlock)(int32_t decoderState);
typedef void (^AviationReportOutputErrorBlock)(NSString *message, NSString *code);

// ---------------------------------------------------------------------------
// Engine attachment
// ---------------------------------------------------------------------------

/**
 * Engine-scoped hooks handed to optional subsystems in other packages.
 *
 * Carries the concrete engine identity and callbacks rather than exposing
 * process-global "current engine" state. Subsystems observe transitions and
 * guard commands through here without sharing the engine's state vocabulary.
 */
// Recorder pause/resume hooks (installed by the owning engine).
// pause: returns @(shouldResume) after pausing a PLAYING transport, or nil
// if the transport wasn't playing. resume: plays iff still paused; the
// policy decision was already captured into the receipt at pause time.
typedef NSNumber * _Nullable (^AviationRecorderPauseBlock)(void);
typedef void (^AviationRecorderResumeBlock)(void);

@interface AviationEngineAttachment : NSObject

@property (nonatomic, copy) NSString *engineId;

@property (nonatomic, copy, nullable) AviationInstallCommandGuardBlock installCommandGuardBlock;
@property (nonatomic, copy, nullable) AviationClearCommandGuardBlock clearCommandGuardBlock;
@property (nonatomic, copy, nullable) AviationInstallPlaybackOutputBlock installPlaybackOutputBlock;
@property (nonatomic, copy, nullable) AviationClearPlaybackOutputBlock clearPlaybackOutputBlock;
@property (nonatomic, copy, nullable) AviationReportOutputTimeBlock reportOutputTimeBlock;
@property (nonatomic, copy, nullable) AviationReportOutputStateBlock reportOutputStateBlock;
@property (nonatomic, copy, nullable) AviationReportOutputErrorBlock reportOutputErrorBlock;
@property (nonatomic, copy, nullable) AviationDomainEventSubscribeBlock domainEventSubscribeBlock;
@property (nonatomic, copy, nullable) AviationDomainEventUnsubscribeBlock domainEventUnsubscribeBlock;
@property (nonatomic, copy, nullable) AviationStateChangeSubscribeBlock stateChangeSubscribeBlock;

@property (nonatomic, copy, nullable) AviationRecorderPauseBlock recorderPauseBlock;
@property (nonatomic, copy, nullable) AviationRecorderResumeBlock recorderResumeBlock;

- (instancetype)initWithEngineId:(NSString *)engineId;

- (void)installCommandGuardWithOwner:(NSObject *)owner block:(AviationCommandGuardBlock)block;
- (void)clearCommandGuardWithOwner:(NSObject *)owner;

- (void)installPlaybackOutputWithOwner:(NSObject *)owner output:(id<AviationPlaybackOutput>)output;
- (void)clearPlaybackOutputWithOwner:(NSObject *)owner;

/// Feedback from an installed output, in the vocabulary the local decoder uses.
/// The coordinator consumes both identically, which is what keeps the state
/// machine authoritative while playback is remote.
- (void)reportOutputTimeWithCurrentMs:(double)currentMs
                           durationMs:(double)durationMs
                      seekableStartMs:(double)seekableStartMs
                        seekableEndMs:(double)seekableEndMs
                               isLive:(BOOL)isLive NS_SWIFT_NAME(reportOutputTime(currentMs:durationMs:seekableStartMs:seekableEndMs:isLive:));
- (void)reportOutputState:(int32_t)decoderState;
- (void)reportOutputError:(NSString *)message code:(NSString *)code;
- (uint32_t)subscribeToDomainEvents:(void (^)(int32_t type, int32_t queueIndex))callback NS_SWIFT_NAME(subscribe(toDomainEvents:));
- (void)unsubscribeDomainEvent:(uint32_t)subscriptionId;
- (nullable AviationStateChangeUnsubscribeBlock)subscribeToStateChanges:(void (^)(int32_t state))callback NS_SWIFT_NAME(subscribe(toStateChanges:));

@end

// ---------------------------------------------------------------------------
// VideoView attachment
// ---------------------------------------------------------------------------

/**
 * Per-engine attachment passed to optional VideoView sidecars such as IMA.
 * Adds the rendering surface and ad hooks to the engine-scoped base.
 */
@interface AviationVideoViewAttachment : AviationEngineAttachment

@property (nonatomic, weak, nullable) AVPlayer *player;
@property (nonatomic, copy) NSString *adTagUrl;

@property (nonatomic, copy, nullable) AviationVoidBlock contentPauseBlock;
@property (nonatomic, copy, nullable) AviationVoidBlock contentResumeBlock;
@property (nonatomic, copy, nullable) AviationSetAdModeBlock setAdModeBlock;
@property (nonatomic, copy, nullable) AviationVoidBlock clearAdModeBlock;
@property (nonatomic, copy, nullable) AviationEmitAdDomainEventBlock emitAdDomainEventBlock;

- (instancetype)initWithPlayer:(AVPlayer *)player
                       engineId:(NSString *)engineId
                       adTagUrl:(NSString *)adTagUrl;

- (void)contentPauseRequested;
- (void)contentResumeRequested;
- (void)setNowPlayingAdModeWithTitle:(NSString *)title durationSeconds:(double)durationSeconds NS_SWIFT_NAME(setNowPlayingAdMode(withTitle:durationSeconds:));
- (void)clearNowPlayingAdMode;
- (void)emitAdDomainEventWithType:(int32_t)type
                       breakIndex:(int32_t)breakIndex
                       breakTimeMs:(double)breakTimeMs
                   totalAdsInBreak:(int32_t)totalAdsInBreak
                              adId:(nullable NSString *)adId
                             title:(nullable NSString *)title
                        durationMs:(double)durationMs
                         currentMs:(double)currentMs
                    adIndexInBreak:(int32_t)adIndexInBreak
               adTotalAdsInBreak:(int32_t)adTotalAdsInBreak
                       isSkippable:(BOOL)isSkippable
                      skipOffsetMs:(double)skipOffsetMs
                      errorMessage:(nullable NSString *)errorMessage NS_SWIFT_NAME(emitAdDomainEvent(withType:breakIndex:breakTimeMs:totalAdsInBreak:adId:title:durationMs:currentMs:adIndexInBreak:adTotalAdsInBreak:isSkippable:skipOffsetMs:errorMessage:));

@end

// ---------------------------------------------------------------------------
// VideoView plugin registry
// ---------------------------------------------------------------------------

@protocol AviationVideoViewPlugin <NSObject>

- (void)onVideoViewAttachedWithAttachment:(AviationVideoViewAttachment *)attachment
                                container:(UIView *)container
                           viewController:(nullable UIViewController *)viewController;

- (void)onVideoViewDetached;

@end

/**
 * Pure ObjC plugin registry for optional native VideoView sidecars.
 *
 * Plugin packages import this ObjC header directly because importing the
 * Aviation Swift module from plugin pods is not reliable with C++ headers.
 */
/**
 * One engine paused by the recorder. shouldResume snapshots that engine's
 * interruption auto-resume policy at pause time; resumeEngines() replays it
 * mechanically without consulting anyone.
 */
@interface AviationPauseReceipt : NSObject
@property (nonatomic, readonly, copy) NSString *engineId;
@property (nonatomic, readonly) BOOL shouldResume;
@end

@interface AviationEngineRegistry : NSObject

+ (void)registerVideoViewPlugin:(id<AviationVideoViewPlugin>)plugin;
+ (void)unregisterVideoViewPlugin:(id<AviationVideoViewPlugin>)plugin;
+ (void)notifyVideoViewAttachedWithAttachment:(AviationVideoViewAttachment *)attachment
                                    container:(UIView *)container
                               viewController:(nullable UIViewController *)viewController;
+ (void)notifyVideoViewDetached;

/**
 * Engine attachments, keyed by engineId. An engine registers itself on
 * creation so subsystems created independently — a recorder, an analytics
 * sink — can bind to it by id.
 */
+ (void)registerEngineAttachment:(AviationEngineAttachment *)attachment NS_SWIFT_NAME(register(engineAttachment:));
+ (void)unregisterEngineAttachmentForEngineId:(NSString *)engineId NS_SWIFT_NAME(unregisterEngineAttachment(engineId:));
+ (nullable AviationEngineAttachment *)attachmentForEngineId:(NSString *)engineId NS_SWIFT_NAME(attachment(engineId:));

/// Pauses every PLAYING engine's transport for capture. Returns one receipt
/// per engine actually paused; shouldResume snapshots that engine's current
/// auto-resume policy. Already-idle engines are untouched and get no receipt
/// (they must not be resumed later).
+ (NSArray<AviationPauseReceipt *> *)pausePlayingEngines NS_SWIFT_NAME(pausePlayingEngines());

/// Mechanical replay of receipts: plays engines still alive and still
/// paused. Policy was snapshotted at pause time and is not re-read here.
+ (void)resumeEngines:(NSArray<AviationPauseReceipt *> *)receipts NS_SWIFT_NAME(resumeEngines(_:));

/// YES while a recorder-initiated pause batch is outstanding. The
/// becoming-noisy 'ignore' counterattack checks this so the two features
/// never fight over the same transport.
+ (BOOL)isRecorderPauseActive;
+ (void)setRecorderPauseActive:(BOOL)active;

@end

NS_ASSUME_NONNULL_END
