/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#import "VibratorManager.h"
#import <UIKit/UIKit.h>

constexpr int32_t ERROR = -1;
constexpr int32_t SUCCESS = 0;
constexpr int32_t PARAMETER_ERROR = 401;
constexpr int32_t TIEM_OUT_MAX = 1800000;
constexpr float POINT_SHARPNESS = 50.0f;

@implementation VibratorInfoObject
@end

@implementation EffectInfo
@end

#pragma mark - VibratorManager 

@interface VibratorManager ()
@property (nonatomic, strong) CHHapticEngine *hapticEngine;
@property (nonatomic, strong) id<CHHapticPatternPlayer> patternPlayer;
@property (nonatomic, assign) BOOL isHapticEngineRunning;
@property (nonatomic, assign) BOOL isVibrating;
@property (nonatomic, strong) NSMutableArray<NSTimer *> *activeTimers;
@property (nonatomic, assign) dispatch_queue_t vibrationQueue;
@property (nonatomic, strong) NSDictionary<NSString *, NSDictionary *> *effectMapping;
@property (nonatomic, strong) UIImpactFeedbackGenerator *impactGenerator;
@property (nonatomic, strong) UINotificationFeedbackGenerator *notificationGenerator;
@property (nonatomic, strong) UISelectionFeedbackGenerator *selectionGenerator;
@end

@implementation VibratorManager

+ (instancetype)sharedInstance {
    static VibratorManager *shared = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shared = [[self alloc] init];
    });
    return shared;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _vibrationQueue = dispatch_queue_create("com.arkuix.vibrator.queue", DISPATCH_QUEUE_SERIAL);
        _activeTimers = [NSMutableArray array];

        self.isVibrating = NO;

        [self setupEffectMapping];
        [self initIalizeHapticEngine];
        [self initIalizeFeedbackGenerators];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(appDidEnterBackground:)
                                                     name:UIApplicationDidEnterBackgroundNotification
                                                   object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(appWillEnterForeground:)
                                                     name:UIApplicationWillEnterForegroundNotification
                                                   object:nil];
    }
    return self;
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    dispatch_async(self.vibrationQueue, ^{
        [self stopVibrator];
    });

    [self stopHapticEngine];
}

#pragma mark - Lifecycle Management

- (void)setupEffectMapping {
    self.effectMapping = @{
        @"haptic.clock.timer": @{@"type": @"continuous", @"intensity": @0.8, @"sharpness": @0.5, @"duration": @2.0},
        @"haptic.effect.hard": @{@"type": @"transient", @"intensity": @0.6, @"sharpness": @0.5, @"duration": @0.05},
        @"haptic.effect.soft": @{@"type": @"transient", @"intensity": @0.5, @"sharpness": @0.3, @"duration": @0.03},
        @"haptic.effect.sharp": @{@"type": @"transient", @"intensity": @0.5, @"sharpness": @0.8, @"duration": @0.02},
        @"haptic.notice.success": @{
            @"type": @"pattern",
            @"events": @[
                @{@"type": @"transient", @"time": @0.0, @"intensity": @0.8, @"sharpness": @0.6, @"duration": @0.17},
                @{@"type": @"transient", @"time": @0.25, @"intensity": @0.8, @"sharpness": @0.6, @"duration": @0.17}
            ],
        },
        @"haptic.notice.fail": @{
            @"type": @"pattern", 
            @"events": @[
                @{@"type": @"transient", @"time": @0.0, @"intensity": @0.9, @"sharpness": @0.3, @"duration": @0.25},
                @{@"type": @"transient", @"time": @0.2, @"intensity": @0.9, @"sharpness": @0.3, @"duration": @0.25}
            ],
        },
        @"haptic.notice.warning": @{
            @"type": @"pattern",
            @"events": @[
                @{@"type": @"continuous", @"time": @0.0, @"intensity": @0.9, @"sharpness": @0.5, @"duration": @0.2},
                @{@"type": @"continuous", @"time": @1.0, @"intensity": @0.9, @"sharpness": @0.5, @"duration": @0.2},
                @{@"type": @"continuous", @"time": @2.0, @"intensity": @0.9, @"sharpness": @0.5, @"duration": @0.2}
            ],
        }
    };
}

- (void)initIalizeFeedbackGenerators {
    if (@available(iOS 10.0, *)) {
        _impactGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium];
        [_impactGenerator prepare];
        _notificationGenerator = [[UINotificationFeedbackGenerator alloc] init];
        [_notificationGenerator prepare];
        _selectionGenerator = [[UISelectionFeedbackGenerator alloc] init];
        [_selectionGenerator prepare];
    }
}

- (void)initIalizeHapticEngine {
    if (@available(iOS 13.0, *)) {
        if (![CHHapticEngine.capabilitiesForHardware supportsHaptics]) {
            NSLog(@"Device does not support Core Haptics");
            return;
        }
        NSError *error = nil;
        _hapticEngine = [[CHHapticEngine alloc] initAndReturnError:&error];
        if (error) {
            NSLog(@"Haptic engine creation error: %@", error.localizedDescription);
            return;
        }

        if (!_hapticEngine) {
            NSLog(@"Haptic engine is nil after initialization attempts");
            return;
        }
        __weak __typeof(self) weakSelf = self;
        _hapticEngine.resetHandler = ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                __strong __typeof(weakSelf) strongSelf = weakSelf;
                if (!strongSelf) {
                    return;
                }
                [strongSelf startHapticEngine];
            });
        };
        _hapticEngine.stoppedHandler = ^(CHHapticEngineStoppedReason reason) {
            NSLog(@"Haptic engine stopped: %ld", (long)reason);
        };

        [self startHapticEngine];
    }
}

- (void)startHapticEngine {
    if (@available(iOS 13.0, *)) {
        if (!_hapticEngine) {
            NSLog(@"Haptic engine is not initialized,_hapticEngine is nil");
            return;
        }
        NSError *error = nil;
        [_hapticEngine startAndReturnError:&error];
        if (error) {
            NSLog(@"Failed to start haptic engine: %@", error.localizedDescription);
        } else {
            _isHapticEngineRunning = YES;
        }
    }
}

- (void)stopHapticEngine {
    if (@available(iOS 13.0, *)) {
        if (!_hapticEngine) {
            NSLog(@"Haptic engine is not initialized,_hapticEngine is nil");
            return;
        }
        [_hapticEngine stopWithCompletionHandler:^(NSError *error) {
            if (error) {
                NSLog(@"Error stopping haptic engine: %@", error.localizedDescription);
            } else {
                self->_isHapticEngineRunning = NO;
            }
        }];
    }
}

- (int32_t)vibrateWithTimeOut:(int32_t)timeOut {
    [self setCurrentMode:VibratorModeTime];
    if (timeOut <= 0 || timeOut > TIEM_OUT_MAX) {
        NSLog(@"vibrateWithTimeOut timeOut invalid, timeOut:%dms", timeOut);
        return PARAMETER_ERROR;
    }
    if (self.isVibrating) {
        NSLog(@"vibrateWithTimeOut already vibrating, stop first.");
        [self stopVibrator];
    }

    self.isVibrating = YES;
    
    if (@available(iOS 13.0, *)) {
        [self playVibrationWithDuration:timeOut/1000.0];
    } else {
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
    }
    return SUCCESS;
}

- (void)playVibrationWithDuration:(NSTimeInterval)duration {
    CGFloat intensity = 1.0;
    CGFloat sharpness = 1.0;
    
    [self playVibrationCoreWithDuration:duration intensity:intensity sharpness:sharpness];
}

- (int32_t)stopVibrator {
    if (!self.isVibrating) {
        NSLog(@"No active vibration to stop");
        return SUCCESS;
    }
    for (NSTimer *timer in self.activeTimers) {
        if ([timer isValid]) {
            [timer invalidate];
            NSLog(@"Invalidated timer: %@", timer);
        }
    }
    [self.activeTimers removeAllObjects];
    if (@available(iOS 13.0, *) && self.patternPlayer) {
        NSError *error = nil;
        [self.patternPlayer stopAtTime:0 error:&error];
        if (error) {
            NSLog(@"Error stopping pattern player: %@", error.localizedDescription);
        }
        self.patternPlayer = nil;
    }
    self.isVibrating = NO;
    return SUCCESS;
}

- (int32_t)playVibratorEffect:(NSString *)effect loopCount:(int32_t)loopCount {
    if (!@available(iOS 13.0, *)) {
        NSLog(@"playVibratorEffect error: version not support ");
        return ERROR;
    }

    [self setCurrentMode:VibratorModePreset];
    if (!effect || effect.length == 0) {
        NSLog(@"playVibratorEffect error: effect is nil or empty");
        return PARAMETER_ERROR;
    }

    NSDictionary *effectConfig = self.effectMapping[effect];
    if (!effectConfig) {
        NSLog(@"playVibratorEffect error: effect config not found: %@", effect);
        return ERROR;
    }
    self.isVibrating = YES;
    NSString *effectType = effectConfig[@"type"];
    if ([effectType isEqualToString:@"pattern"]) {
        NSArray *events = effectConfig[@"events"];
        return [self playHapticPattern:events loopCount:loopCount];
    } else {
        float intensity = [effectConfig[@"intensity"] floatValue];
        float sharpness = [effectConfig[@"sharpness"] floatValue];
        float duration = [effectConfig[@"duration"] floatValue];
        return [self playHaptic:intensity sharpness:sharpness duration:duration loopCount:loopCount];
    }
}

- (int32_t)playHapticPattern:(NSArray *)events loopCount:(int32_t)loopCount {
    if (!_hapticEngine || !_isHapticEngineRunning) {
        NSLog(@"HapticEngine not available");
        return ERROR;
    }
    NSError *error = nil;
    NSMutableArray<CHHapticEvent *> *hapticEvents = [NSMutableArray array];
    for (int loop = 0; loop < MAX(1, loopCount); loop++) {
        NSTimeInterval loopStartTime = 0;
        if (loop > 0) {
            loopStartTime = loop * [self calculatePatternDuration:events];
        }
        for (NSDictionary *eventConfig in events) {
            NSTimeInterval eventTime = loopStartTime + [eventConfig[@"time"] doubleValue];
            float intensity = [eventConfig[@"intensity"] floatValue];
            float sharpness = [eventConfig[@"sharpness"] floatValue];
            float duration = [eventConfig[@"duration"] floatValue];
            CHHapticEventType eventType;
            NSString *eventTypeStr = eventConfig[@"type"];
            if (eventTypeStr) {
                if ([eventTypeStr isEqualToString:@"continuous"]) {
                    eventType = CHHapticEventTypeHapticContinuous;
                } else {
                    eventType = CHHapticEventTypeHapticTransient;
                }
            } else {
                eventType = CHHapticEventTypeHapticTransient;
            }

            CHHapticEventParameter *intensityParam = [[CHHapticEventParameter alloc] 
                initWithParameterID:CHHapticEventParameterIDHapticIntensity value:intensity];
            CHHapticEventParameter *sharpnessParam = [[CHHapticEventParameter alloc] 
                initWithParameterID:CHHapticEventParameterIDHapticSharpness value:sharpness];
            
            CHHapticEvent *event = [[CHHapticEvent alloc] 
                initWithEventType:eventType
                parameters:@[intensityParam, sharpnessParam]
                relativeTime:eventTime
                duration:duration];
            
            [hapticEvents addObject:event];
        }
    }

    CHHapticPattern *pattern = [[CHHapticPattern alloc] initWithEvents:hapticEvents parameters:@[] error:&error];

    if (error) {
        NSLog(@"Error creating pattern: %@", error);
        return ERROR;
    }

    id<CHHapticPatternPlayer> player = [_hapticEngine createPlayerWithPattern:pattern error:&error];
    if (error) {
        NSLog(@"Error creating player: %@", error);
        return ERROR;
    }

    [player startAtTime:0 error:&error];
    if (error) {
        NSLog(@"Error starting player: %@", error);
        return ERROR;
    }

    self.patternPlayer = player;
    return SUCCESS;
}

- (NSTimeInterval)calculatePatternDuration:(NSArray *)events {
    NSTimeInterval maxTime = 0;
    for (NSDictionary *eventConfig in events) {
        NSTimeInterval eventEndTime = [eventConfig[@"time"] doubleValue] + [eventConfig[@"duration"] doubleValue];
        if (eventEndTime > maxTime) {
            maxTime = eventEndTime;
        }
    }
    return maxTime;
}

- (int32_t)playHaptic:(float)intensity sharpness:(float)sharpness duration:(float)duration loopCount:(int32_t)loopCount {
    if (!_hapticEngine || !_isHapticEngineRunning) {
        NSLog(@"HapticEngine create failed or not running");
        return ERROR;
    }
    NSError *error = nil;
    NSMutableArray<CHHapticEvent *> *events = [NSMutableArray array];
    float gap = 0.1;
    for (int i = 0; i < MAX(1, loopCount); i++) {
        CHHapticEventParameter *intensityParam = [[CHHapticEventParameter alloc] 
                                                    initWithParameterID:CHHapticEventParameterIDHapticIntensity 
                                                    value:intensity];
        CHHapticEventParameter *sharpnessParam = [[CHHapticEventParameter alloc] 
                                                    initWithParameterID:CHHapticEventParameterIDHapticSharpness 
                                                    value:sharpness];
        float startTime = i * (duration + gap);
        CHHapticEvent *event = [[CHHapticEvent alloc] 
                                initWithEventType:CHHapticEventTypeHapticContinuous 
                                parameters:@[intensityParam, sharpnessParam] 
                                relativeTime:startTime duration:duration];
        [events addObject:event];
    }
    CHHapticPattern *pattern = [[CHHapticPattern alloc] initWithEvents:events parameters:@[] error:&error];
    if (!error) {
        id<CHHapticPatternPlayer> player = [_hapticEngine createPlayerWithPattern:pattern error:&error];
        if (player == nil || error) {
            NSLog(@"player is nul or error: %@", error);
            return ERROR;
        }
        [player startAtTime:0 error:&error];
        if (!error) {
            self.patternPlayer = player;
            return SUCCESS;
        } else {
            NSLog(@"startAtTime is error: %@", error);
        }
    }
    return ERROR;
}

- (BOOL)isSupportEffect:(NSString *)effect {
    BOOL supported = self.effectMapping[effect] != nil;
    return supported;
}

- (NSArray<VibratorInfoObject *> *)getVibratorList {
    VibratorInfoObject *vibrator = [[VibratorInfoObject alloc] init];
    vibrator.deviceId = -1;
    vibrator.vibratorId = -1;
    vibrator.deviceName = @"iOS Taptic Engine";
    vibrator.isSupportHdHaptic = [self supportsCoreHaptics];
    vibrator.isLocalVibrator = YES;
    vibrator.position = 0;
    return @[vibrator];
}

- (EffectInfo *)getEffectInfo:(NSString *)effectType {
    EffectInfo *info = [[EffectInfo alloc] init];

    NSDictionary *effectConfig = self.effectMapping[effectType];
    if (effectConfig) {
        NSLog(@"getEffectInfo effectConfig found for: %@", effectType);
        info.duration = @([effectConfig[@"duration"] floatValue]);
        info.isSupportEffect = YES;
    } else {
        NSLog(@"getEffectInfo effectConfig not found for: %@", effectType);
        info.isSupportEffect = NO;
    }
    return info;
}

- (BOOL)supportsCoreHaptics {
    if (@available(iOS 13.0, *)) {
        return [CHHapticEngine.capabilitiesForHardware supportsHaptics];
    }
    return NO;
}

- (void)playVibrationCoreWithDuration:(float)duration intensity:(float)intensity sharpness:(float)sharpness {
    NSError *error = nil;
    CHHapticEventParameter *intensityParam = [[CHHapticEventParameter alloc] 
                                                initWithParameterID:CHHapticEventParameterIDHapticIntensity 
                                                value:intensity];
    CHHapticEventParameter *sharpnessParam = [[CHHapticEventParameter alloc] 
                                                initWithParameterID:CHHapticEventParameterIDHapticSharpness 
                                                value:sharpness];
    CHHapticEvent *event = [[CHHapticEvent alloc] 
                            initWithEventType:CHHapticEventTypeHapticContinuous 
                            parameters:@[intensityParam, sharpnessParam] 
                            relativeTime:0 duration:duration];
    CHHapticPattern *pattern = [[CHHapticPattern alloc] initWithEvents:@[event] parameters:@[] error:&error];
    if (!error) {
        id<CHHapticPatternPlayer> player = [_hapticEngine createPlayerWithPattern:pattern error:&error];
        if (player == nil || error) {
            NSLog(@"player is nul or error: %@", error);
            return;
        }
        [player startAtTime:0 error:&error];
        if (!error) {
            self.patternPlayer = player;
            return;
        } else {
            NSLog(@"startAtTime is error: %@", error);
        }
    }
}

- (void)playPattern:(const OHOS::Sensors::VibratePattern &)pattern {
    if (self.isVibrating) {
        NSLog(@"playPattern already vibrating, stop first.");
        [self stopVibrator];
    }
    [self setCurrentMode:OtherMode];
    NSError *error = nil;
    CHHapticPattern *hapticPattern = [self createHapticPatternFromPattern:pattern error:&error];

    if (error || !hapticPattern) {
        NSLog(@"Failed to create haptic pattern: %@", error);
        return;
    }
    [self playHapticPattern:hapticPattern];
}

- (CHHapticEvent *)createHapticEventFromVibrateEvent:(const OHOS::Sensors::VibrateEvent &)event {
    NSTimeInterval eventTime = event.time / 1000.0;
    NSTimeInterval eventDuration = event.duration / 1000.0;

    CHHapticEventType eventType = (event.tag == OHOS::Sensors::EVENT_TAG_CONTINUOUS)
        ? CHHapticEventTypeHapticContinuous
        : CHHapticEventTypeHapticTransient;

    float intensity = event.intensity / 100.0f;
    float sharpness = event.frequency / 100.0f;

    NSArray<CHHapticEventParameter *> *parameters = @[
        [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticIntensity value:intensity],
        [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticSharpness value:sharpness]
    ];

    return [[CHHapticEvent alloc] initWithEventType:eventType
                                  parameters:parameters
                                  relativeTime:eventTime
                                  duration:eventDuration];
}

- (NSArray<CHHapticParameterCurve *> *)createCurvesFromVibrateEvent:(const OHOS::Sensors::VibrateEvent &)event {
    if (event.points.empty()) {
        return @[];
    }
    std::vector<OHOS::Sensors::VibrateCurvePoint> sortedPoints = event.points;
    std::sort(sortedPoints.begin(), sortedPoints.end());

    NSTimeInterval eventTime = event.time / 1000.0;
    NSMutableArray<CHHapticParameterCurve *> *curves = [NSMutableArray array];
    NSMutableArray<CHHapticParameterCurveControlPoint *> *intensityPoints = [NSMutableArray array];
    for (const OHOS::Sensors::VibrateCurvePoint &point : sortedPoints) {
        CHHapticParameterCurveControlPoint *controlPoint = [[CHHapticParameterCurveControlPoint alloc]
            initWithRelativeTime:point.time / 1000.0
            value:point.intensity / 100.0f];
        [intensityPoints addObject:controlPoint];
    }
    CHHapticParameterCurve *intensityCurve = [[CHHapticParameterCurve alloc]
        initWithParameterID:CHHapticDynamicParameterIDHapticIntensityControl
        controlPoints:intensityPoints
        relativeTime:eventTime];
    [curves addObject:intensityCurve];
    NSMutableArray<CHHapticParameterCurveControlPoint *> *sharpnessPoints = [NSMutableArray array];
    for (const OHOS::Sensors::VibrateCurvePoint &point : sortedPoints) {
        CHHapticParameterCurveControlPoint *controlPoint = [[CHHapticParameterCurveControlPoint alloc]
            initWithRelativeTime:point.time / 1000.0
            value:point.frequency / 100.0f];
        [sharpnessPoints addObject:controlPoint];
    }
    CHHapticParameterCurve *sharpnessCurve = [[CHHapticParameterCurve alloc]
        initWithParameterID:CHHapticDynamicParameterIDHapticSharpnessControl
        controlPoints:sharpnessPoints
        relativeTime:eventTime];
    [curves addObject:sharpnessCurve];

    return curves;
}

- (CHHapticPattern *)createHapticPatternFromPattern:(const OHOS::Sensors::VibratePattern &)pattern error:(NSError **)error {
    NSMutableArray<CHHapticEvent *> *hapticEvents = [NSMutableArray array];
    NSMutableArray<CHHapticParameterCurve *> *parameterCurves = [NSMutableArray array];

    for (const OHOS::Sensors::VibrateEvent &event : pattern.events) {
        CHHapticEvent *hapticEvent = [self createHapticEventFromVibrateEvent:event];
        [hapticEvents addObject:hapticEvent];
        NSArray<CHHapticParameterCurve *> *curves = [self createCurvesFromVibrateEvent:event];
        [parameterCurves addObjectsFromArray:curves];
    }

    return [[CHHapticPattern alloc] initWithEvents:hapticEvents
                                    parameterCurves:parameterCurves
                                    error:error];
}

- (BOOL)playHapticPattern:(CHHapticPattern *)hapticPattern {
    if (!hapticPattern) {
        NSLog(@"playHapticPattern: hapticPattern is nil");
        return NO;
    }
    NSError *error = nil;
    id<CHHapticPatternPlayer> player = [_hapticEngine createPlayerWithPattern:hapticPattern error:&error];
    if (player == nil || error) {
        NSLog(@"Failed to create pattern player: %@", error);
        return NO;
    }
    [player startAtTime:CHHapticTimeImmediate error:&error];
    if (error) {
        NSLog(@"Failed to start pattern player: %@", error);
        return NO;
    }

    self.patternPlayer = player;
    self.isVibrating = YES;
    return YES;
}

- (void)playPatterns:(const std::vector<OHOS::Sensors::VibratePattern> &)patterns {
    if (self.isVibrating) {
        NSLog(@"playPatterns already vibrating, stop first.");
        [self stopVibrator];
    }
    [self setCurrentMode:OtherMode];
    NSDictionary *hapticComponents = [self convertPatternsToHapticComponents:patterns];
    NSArray<CHHapticEvent *> *allHapticEvents = hapticComponents[@"events"];
    NSArray<CHHapticParameterCurve *> *allParameterCurves = hapticComponents[@"curves"];
    [self createAndPlayHapticPatternWithEvents:allHapticEvents curves:allParameterCurves];
    NSLog(@"playPatterns leave");
}

- (NSDictionary *)convertPatternsToHapticComponents:(const std::vector<OHOS::Sensors::VibratePattern> &)patterns {
    NSMutableArray<CHHapticEvent *> *allHapticEvents = [NSMutableArray array];
    NSMutableArray<CHHapticParameterCurve *> *allParameterCurves = [NSMutableArray array];
    for (const OHOS::Sensors::VibratePattern &pattern : patterns) {
        [self processVibratePattern:pattern
                   intoHapticEvents:allHapticEvents
                 andParameterCurves:allParameterCurves];
    }
    return @{
        @"events": allHapticEvents,
        @"curves": allParameterCurves
    };
}

- (void)processVibratePattern:(const OHOS::Sensors::VibratePattern &)pattern
             intoHapticEvents:(NSMutableArray<CHHapticEvent *> *)hapticEvents
           andParameterCurves:(NSMutableArray<CHHapticParameterCurve *> *)parameterCurves {
    NSTimeInterval patternStartTime = (NSTimeInterval)pattern.startTime / 1000.0;
    for (const OHOS::Sensors::VibrateEvent &event : pattern.events) {
        NSTimeInterval eventTime = patternStartTime + ((NSTimeInterval)event.time / 1000.0);
        CHHapticEvent *hapticEvent = [self createHapticEventFromVibrateEvent:event
                                                                    eventTime:eventTime];
        [hapticEvents addObject:hapticEvent];
        if (!event.points.empty()) {
            [self addParameterCurvesForEvent:event
                                   eventTime:eventTime
                     toParameterCurvesArray:parameterCurves];
        }
    }
}

- (CHHapticEvent *)createHapticEventFromVibrateEvent:(const OHOS::Sensors::VibrateEvent &)event
                                           eventTime:(NSTimeInterval)eventTime {
    NSTimeInterval eventDuration = (NSTimeInterval)event.duration / 1000.0;
    float intensity = event.intensity / 100.0f;
    float sharpness = event.frequency / 100.0f;
    NSArray<CHHapticEventParameter *> *parameters = @[
        [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticIntensity value:intensity],
        [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticSharpness value:sharpness]
    ];
    if (event.tag == OHOS::Sensors::EVENT_TAG_CONTINUOUS) {
        return [[CHHapticEvent alloc] initWithEventType:CHHapticEventTypeHapticContinuous
                                            parameters:parameters
                                            relativeTime:eventTime
                                            duration:eventDuration];
    } else {
        return [[CHHapticEvent alloc] initWithEventType:CHHapticEventTypeHapticTransient
                                            parameters:parameters
                                            relativeTime:eventTime];
    }
}

- (void)addParameterCurvesForEvent:(const OHOS::Sensors::VibrateEvent &)event
                         eventTime:(NSTimeInterval)eventTime
           toParameterCurvesArray:(NSMutableArray<CHHapticParameterCurve *> *)parameterCurves {
    std::vector<OHOS::Sensors::VibrateCurvePoint> sortedPoints = event.points;
    std::sort(sortedPoints.begin(), sortedPoints.end());
    NSMutableArray<CHHapticParameterCurveControlPoint *> *intensityPoints = [NSMutableArray array];
    NSMutableArray<CHHapticParameterCurveControlPoint *> *sharpnessPoints = [NSMutableArray array];

    for (const OHOS::Sensors::VibrateCurvePoint &point : sortedPoints) {
        NSTimeInterval pointTime = eventTime + (point.time / 1000.0);
        float pointIntensity = event.intensity * point.intensity / 100.0f;
        float pointSharpness = (event.frequency + point.frequency) / 100.0f + 0.5f;
        if (pointSharpness < 0.0f) {
            pointSharpness = POINT_SHARPNESS / 100.0f;
        }

        CHHapticParameterCurveControlPoint *intensityControlPoint = [[CHHapticParameterCurveControlPoint alloc]
            initWithRelativeTime:pointTime
            value:pointIntensity];
        [intensityPoints addObject:intensityControlPoint];
        CHHapticParameterCurveControlPoint *sharpnessControlPoint = [[CHHapticParameterCurveControlPoint alloc]
            initWithRelativeTime:pointTime
            value:pointSharpness];
        [sharpnessPoints addObject:sharpnessControlPoint];
    }
    if (intensityPoints.count > 0) {
        CHHapticParameterCurve *intensityCurve = [[CHHapticParameterCurve alloc]
            initWithParameterID:CHHapticDynamicParameterIDHapticIntensityControl
            controlPoints:intensityPoints
            relativeTime:eventTime];
        [parameterCurves addObject:intensityCurve];
    }
    if (sharpnessPoints.count > 0) {
        CHHapticParameterCurve *sharpnessCurve = [[CHHapticParameterCurve alloc]
            initWithParameterID:CHHapticDynamicParameterIDHapticSharpnessControl
            controlPoints:sharpnessPoints
            relativeTime:eventTime];
        [parameterCurves addObject:sharpnessCurve];
    }
}

- (void)createAndPlayHapticPatternWithEvents:(NSArray<CHHapticEvent *> *)events
                                      curves:(NSArray<CHHapticParameterCurve *> *)curves {

    NSError *error = nil;
    CHHapticPattern *hapticPattern = [[CHHapticPattern alloc] 
                                    initWithEvents:events
                                    parameterCurves:curves
                                    error:&error];
    if (error) {
        NSLog(@"Error creating haptic pattern: %@", error);
        return;
    }
    id<CHHapticPatternPlayer> player = [_hapticEngine createPlayerWithPattern:hapticPattern error:&error];
    if (player == nil || error) {
        NSLog(@"player is nul or error: %@", error);
        return;
    }
    [player startAtTime:CHHapticTimeImmediate error:&error];
    if (error) {
        NSLog(@"Error starting haptic player: %@", error);
        return;
    }
    self.patternPlayer = player;
    self.isVibrating = YES;
}

- (void)appDidEnterBackground:(NSNotification *)notification {
    [self stopVibrator];
    [self stopHapticEngine];
}

- (void)appWillEnterForeground:(NSNotification *)notification {
    [self startHapticEngine];
}

- (void)setCurrentMode:(VibratorMode)mode {
    _currentMode = mode;
    self.isVibrating = YES;
}

- (int32_t)stopVibratorByMode:(NSString *)mode {
    NSString *modeLower = [mode lowercaseString];
    VibratorMode vibratorMode;
    if ([modeLower isEqualToString:@"time"]) {
        vibratorMode = VibratorModeTime;
    } else if ([modeLower isEqualToString:@"preset"]) {
        vibratorMode = VibratorModePreset;
    }
    if (_currentMode == vibratorMode ) {
        return [self stopVibrator];
    } else {
        return SUCCESS;
    }
}
@end