//
//  RCTOMPlayerView.m
//  OMPlayer
//
//  Created by lcg on 2017/1/20.
//  Copyright © 2017年 Anren. All rights reserved.
//

#import "RCTOMPlayerView.h"
#import "IJKMediaFramework/IJKMediaFramework.h"
#import "UIView+React.h"

@interface RCTOMPlayerView()

@property (nonatomic, retain) IJKFFMoviePlayerController* player;
@property (nonatomic, retain) NSTimer* timer;

@property (nonatomic, strong) NSString* src;
@property (nonatomic, strong) NSString* resizeMode;
@property (nonatomic, assign) BOOL repeat;
@property (nonatomic, assign) BOOL paused;
@property (nonatomic, assign) BOOL muted;
@property (nonatomic, assign) BOOL controls;
@property (nonatomic, assign) float volume;
@property (nonatomic, assign) float rate;
@property (nonatomic, assign) float seek;
@property (nonatomic, assign) BOOL seeking;
@property (nonatomic, assign) float currentTime;
@property (nonatomic, assign) BOOL fullscreen;
@property (nonatomic, assign) BOOL needOnLoadStart;

@property (nonatomic, copy) RCTBubblingEventBlock onOMVideoLoadStart;
@property (nonatomic, copy) RCTBubblingEventBlock onOMVideoLoad;
@property (nonatomic, copy) RCTBubblingEventBlock onOMVideoError;
@property (nonatomic, copy) RCTBubblingEventBlock onOMVideoProgress;
@property (nonatomic, copy) RCTBubblingEventBlock onOMVideoSeek;
@property (nonatomic, copy) RCTBubblingEventBlock onOMVideoEnd;
@property (nonatomic, copy) RCTBubblingEventBlock onOMVideoFullscreenPlayerWillPresent;
@property (nonatomic, copy) RCTBubblingEventBlock onOMVideoFullscreenPlayerDidPresent;
@property (nonatomic, copy) RCTBubblingEventBlock onOMVideoFullscreenPlayerWillDismiss;
@property (nonatomic, copy) RCTBubblingEventBlock onOMVideoFullscreenPlayerDidDismiss;
@property (nonatomic, copy) RCTBubblingEventBlock onOMReadyForDisplay;
@property (nonatomic, copy) RCTBubblingEventBlock onOMPlaybackStalled;
@property (nonatomic, copy) RCTBubblingEventBlock onOMPlaybackResume;
@property (nonatomic, copy) RCTBubblingEventBlock onOMPlaybackRateChange;

@end

@implementation RCTOMPlayerView

- (instancetype)init
{
    if ((self = [super init])) {
        _rate = 1.0;
        _volume = 1.0;
        _resizeMode = @"AVLayerVideoGravityResizeAspectFill";
        _controls = NO;
    }
    
    return self;
}

- (void)removeFromSuperview
{
    [self destoryPlayer];
}

- (void)createPlayer:(NSString*)src
{
//#ifdef DEBUG
//    [IJKFFMoviePlayerController setLogReport:YES];
//    [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_DEBUG];
//#else
    [IJKFFMoviePlayerController setLogReport:NO];
    [IJKFFMoviePlayerController setLogLevel:k_IJK_LOG_INFO];
//#endif
    
    [IJKFFMoviePlayerController checkIfFFmpegVersionMatch:YES];
    
    IJKFFOptions *options = [IJKFFOptions optionsByDefault];
    [options setPlayerOptionIntValue:5 forKey:@"framedrop"];
    
    NSURL *url = [NSURL URLWithString:src];
    if (!url) {
        return ;
    }
    
    self.player = [[IJKFFMoviePlayerController alloc] initWithContentURL:url withOptions:options];
    
    self.player.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
    self.player.view.frame = self.bounds;
    self.player.scalingMode = IJKMPMovieScalingModeAspectFit;
    self.player.shouldAutoplay = YES;
    
    
    self.autoresizesSubviews = YES;
    [self addSubview:self.player.view];
    
    if (self.onOMVideoLoadStart) {
        self.onOMVideoLoadStart(@{@"src":@{
                                        @"uri": src,
                                        @"type": @"",
                                        @"isNetwork": [NSNumber numberWithBool:![url isFileURL]]
                                        },
                                @"target": self.reactTag
                                });
    }
    else {
        _needOnLoadStart = YES;
    }
    
    [self initPlayerTimer];
    [self initNotificationObservers];
    [self.player prepareToPlay];
    

}

- (void)destoryPlayer
{
    [self removeMovieNotificationObservers];
    [self removePlayerTimer];
    if (_player) {
        [_player stop];
        [_player shutdown];
        [_player.view removeFromSuperview];
        _player = nil;
    }
}

- (void)initPlayerTimer
{
    _timer = [NSTimer scheduledTimerWithTimeInterval:0.25
                                              target:self
                                            selector:@selector(progressTimer:)
                                            userInfo:nil
                                             repeats:YES];
}

- (void)removePlayerTimer
{
    if (_timer) {
        [_timer invalidate];
        _timer = nil;
    }
}

- (void)progressTimer:(NSTimer*)timer
{
    if (self.onOMVideoProgress && _player && !_seeking && !_paused) {
        self.onOMVideoProgress(@{@"currentTime": [NSNumber numberWithFloat:_player.currentPlaybackTime],
                               @"playableDuration":[NSNumber numberWithFloat:_player.playableDuration],
                               @"atValue":@"...",
                               @"atTimescale":@"...",
                               @"target": self.reactTag
                               });
    }
}

- (void)setSrc:(NSString *)src
{
    _src = src;
    [self destoryPlayer];
    [self createPlayer:src];
}

- (void)setOnOMVideoLoadStart:(RCTBubblingEventBlock)onOMVideoLoadStart
{
    _onOMVideoLoadStart = onOMVideoLoadStart;
    
    if (_needOnLoadStart)
    {
        NSURL *url = [NSURL URLWithString:_src];
        
        onOMVideoLoadStart(@{@"src":@{
                                     @"uri": _src,
                                     @"type": @"",
                                     @"isNetwork": [NSNumber numberWithBool:![url isFileURL]]
                                     },
                             @"target": self.reactTag
                             });
    }
    
    _needOnLoadStart = NO;
}

#pragma mark - props

- (void)setResizeMode:(NSString *)resizeMode
{
    _resizeMode = resizeMode;
}

- (void)setPaused:(BOOL)paused
{
    if (paused) {
        [self.player pause];
    }
    else {
        [self.player play];
    }
    
    _paused = paused;
}

- (float)getCurrentTime

{
    return _player ? _player.currentPlaybackTime: 0;
}

- (void)setCurrentTime:(float)currentTime
{
    [self setSeek:currentTime];
}

- (void)setSeek:(float)seek
{
    if (_player && _player.isPlaying) {
        
        self.onOMVideoSeek(@{@"currentTime": [NSNumber numberWithFloat:_player.currentPlaybackTime],
                           @"seekTime": [NSNumber numberWithFloat:seek],
                           @"target": self.reactTag
                           });
        
        [_player setCurrentPlaybackTime:seek];
    }
}

- (void)setRate:(float)rate
{
    float oriRate = _rate;
    _rate = rate;
    [self applyModifiers];
    
    float currentRate = _player.playbackRate;
    _player.playbackRate = _rate;
    
    if (_player && currentRate != oriRate && self.onOMPlaybackRateChange) {
        
        self.onOMPlaybackRateChange(@{@"playbackRate": [NSNumber numberWithFloat:currentRate],
                                    @"target": self.reactTag
                                    });
    }
}

- (void)setMuted:(BOOL)muted
{
    _muted = muted;
    [self applyModifiers];
}

- (void)setVolume:(float)volume
{
    _volume = volume;
    [self applyModifiers];
}

- (void)setFullscreen:(BOOL)fullscreen
{
    _fullscreen = fullscreen;
}

- (void)applyModifiers
{
    if (!_player) {
        return ;
    }
    
    if (_muted) {
        _player.playbackVolume = 0;
    } else {
        _player.playbackVolume = _volume;
    }

    [self setResizeMode:_resizeMode];
    [self setRepeat:_repeat];
    [self setPaused:_paused];
    [self setControls:_controls];
}

#pragma mark - notifications

- (void)initNotificationObservers
{
    if (!_player) {
        return ;
    }
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(loadStateDidChange:)
                                                 name:IJKMPMoviePlayerLoadStateDidChangeNotification
                                               object:_player];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(moviePlayBackDidFinish:)
                                                 name:IJKMPMoviePlayerPlaybackDidFinishNotification
                                               object:_player];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(mediaIsPreparedToPlayDidChange:)
                                                 name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
                                               object:_player];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(moviePlayBackStateDidChange:)
                                                 name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
                                               object:_player];
}

-(void)removeMovieNotificationObservers
{
    [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerLoadStateDidChangeNotification object:_player];
    [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerPlaybackDidFinishNotification object:_player];
    [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification object:_player];
    [[NSNotificationCenter defaultCenter]removeObserver:self name:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:_player];
}

- (void)loadStateDidChange:(NSNotification*)notification
{
    //    MPMovieLoadStateUnknown        = 0,
    //    MPMovieLoadStatePlayable       = 1 << 0,
    //    MPMovieLoadStatePlaythroughOK  = 1 << 1, // Playback will be automatically started in this state when shouldAutoplay is YES
    //    MPMovieLoadStateStalled        = 1 << 2, // Playback will be automatically paused in this state, if started
    
    IJKMPMovieLoadState loadState = _player.loadState;
    
    if (loadState != IJKMPMovieLoadStateUnknown && self.onOMVideoLoad) {
        self.onOMVideoLoad(@{
                           @"duration": [NSNumber numberWithFloat:_player.duration],
                           @"currentTime": [NSNumber numberWithFloat:_player.currentPlaybackTime],
                           @"canPlayReverse": @"...",
                           @"canPlayFastForward": @"...",
                           @"canPlaySlowForward": @"...",
                           @"canPlaySlowReverse": @"...",
                           @"canStepBackward": @"...",
                           @"canStepForward": @"...",
                           @"naturalSize": @{
                                   @"width": [NSNumber numberWithFloat:_player.naturalSize.width],
                                   @"height": [NSNumber numberWithFloat:_player.naturalSize.height],
                                   @"orientation": @"unknown"
                                   },
                           @"target": self.reactTag
                           });
    }
    
//    if ((loadState & IJKMPMovieLoadStatePlaythroughOK) != 0) {
//        NSLog(@"loadStateDidChange: IJKMPMovieLoadStatePlaythroughOK: %d\n", (int)loadState);
//    } else if ((loadState & IJKMPMovieLoadStateStalled) != 0) {
//        NSLog(@"loadStateDidChange: IJKMPMovieLoadStateStalled: %d\n", (int)loadState);
//    } else {
//        NSLog(@"loadStateDidChange: ???: %d\n", (int)loadState);
//    }
}

- (void)moviePlayBackDidFinish:(NSNotification*)notification
{
    //    MPMovieFinishReasonPlaybackEnded,
    //    MPMovieFinishReasonPlaybackError,
    //    MPMovieFinishReasonUserExited
    
    [self removePlayerTimer];
    
    int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
    
    switch (reason)
    {
        case IJKMPMovieFinishReasonPlaybackEnded:
            if (_repeat) {
                [self setSrc:_src];
                [self applyModifiers];
            }
            
            break;
            
        case IJKMPMovieFinishReasonUserExited:
            
            break;
            
        case IJKMPMovieFinishReasonPlaybackError:
            NSLog(@"playbackStateDidChange: IJKMPMovieFinishReasonPlaybackError: %d\n", reason);
            if (self.onOMVideoError) {
                self.onOMVideoError(@{@"error":@{
                                            @"code": [NSNumber numberWithInteger:reason],
                                            @"domain": @"..."
                                            },
                                    @"target": self.reactTag
                                    });
            }
            break;
            
        default:
            NSLog(@"playbackPlayBackDidFinish: ???: %d\n", reason);
            break;
    }
    
    if (self.onOMVideoEnd) {
        self.onOMVideoEnd(@{@"target": self.reactTag});
    }
    
    
}

- (void)mediaIsPreparedToPlayDidChange:(NSNotification*)notification
{
    if (self.onOMReadyForDisplay) {
        self.onOMReadyForDisplay(@{@"target": self.reactTag});
    }
}

- (void)moviePlayBackStateDidChange:(NSNotification*)notification
{
    //    MPMoviePlaybackStateStopped,
    //    MPMoviePlaybackStatePlaying,
    //    MPMoviePlaybackStatePaused,
    //    MPMoviePlaybackStateInterrupted,
    //    MPMoviePlaybackStateSeekingForward,
    //    MPMoviePlaybackStateSeekingBackward
    
    switch (_player.playbackState)
    {
        case IJKMPMoviePlaybackStateStopped: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: stoped", (int)_player.playbackState);
            break;
        }
        case IJKMPMoviePlaybackStatePlaying: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: playing", (int)_player.playbackState);
            _seeking = NO;
            if (self.onOMPlaybackResume) {
                self.onOMPlaybackResume(@{@"target": self.reactTag});
            }
            break;
        }
        case IJKMPMoviePlaybackStatePaused: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: paused", (int)_player.playbackState);
            if (self.onOMPlaybackStalled) {
                self.onOMPlaybackStalled(@{@"target": self.reactTag});
            }
            break;
        }
        case IJKMPMoviePlaybackStateInterrupted: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: interrupted", (int)_player.playbackState);
            break;
        }
        case IJKMPMoviePlaybackStateSeekingForward:
        case IJKMPMoviePlaybackStateSeekingBackward: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: seeking", (int)_player.playbackState);
            _seeking = YES;
            break;
        }
        default: {
            NSLog(@"IJKMPMoviePlayBackStateDidChange %d: unknown", (int)_player.playbackState);
            break;
        }
    }
}


@end
