//
//  Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//

#import "OWSDisappearingMessagesConfiguration.h"
#import "NSDate+OWS.h"

NS_ASSUME_NONNULL_BEGIN

// 1 day.
const uint32_t OWSDisappearingMessagesConfigurationDefaultExpirationDuration = kDayInterval;

@interface OWSDisappearingMessagesConfiguration ()

// Transient record lifecycle attributes.
@property (atomic) NSDictionary *originalDictionaryValue;
@property (atomic, getter=isNewRecord) BOOL newRecord;

@end

@implementation OWSDisappearingMessagesConfiguration

- (instancetype)initDefaultWithThreadId:(NSString *)threadId
{
    return [self initWithThreadId:threadId
                          enabled:NO
                  durationSeconds:OWSDisappearingMessagesConfigurationDefaultExpirationDuration];
}

- (nullable instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];

    _originalDictionaryValue = [self dictionaryValue];
    _newRecord = NO;

    return self;
}

- (instancetype)initWithThreadId:(NSString *)threadId enabled:(BOOL)isEnabled durationSeconds:(uint32_t)seconds
{
    self = [super initWithUniqueId:threadId];
    if (!self) {
        return self;
    }

    _enabled = isEnabled;
    _durationSeconds = seconds;
    _originalDictionaryValue = [NSDictionary new];
    _newRecord = YES;

    return self;
}

+ (instancetype)fetchOrCreateDefaultWithThreadId:(NSString *)threadId
{
    OWSDisappearingMessagesConfiguration *savedConfiguration = [self fetchObjectWithUniqueID:threadId];
    if (savedConfiguration) {
        return savedConfiguration;
    } else {
        return [[self alloc] initDefaultWithThreadId:threadId];
    }
}

+ (NSString *)stringForDurationSeconds:(uint32_t)durationSeconds
{
    NSString *amountFormat;
    uint32_t duration;

    uint32_t secondsPerMinute = 60;
    uint32_t secondsPerHour = secondsPerMinute * 60;
    uint32_t secondsPerDay = secondsPerHour * 24;
    uint32_t secondsPerWeek = secondsPerDay * 7;

    if (durationSeconds < secondsPerMinute) { // XX Seconds
        amountFormat = NSLocalizedString(@"TIME_AMOUNT_SECONDS",
            @"{{number of seconds}} embedded in strings, e.g. 'Alice updated disappearing messages "
            @"expiration to {{5 seconds}}'. See other *_TIME_AMOUNT strings");
        duration = durationSeconds;
    } else if (durationSeconds < secondsPerMinute * 1.5) { // 1 Minute
        amountFormat = NSLocalizedString(@"TIME_AMOUNT_SINGLE_MINUTE",
            @"{{1 minute}} embedded in strings, e.g. 'Alice updated disappearing messages "
            @"expiration to {{1 minute}}'. See other *_TIME_AMOUNT strings");
        duration = durationSeconds / secondsPerMinute;
    } else if (durationSeconds < secondsPerHour) { // Multiple Minutes
        amountFormat = NSLocalizedString(@"TIME_AMOUNT_MINUTES",
            @"{{number of minutes}} embedded in strings, e.g. 'Alice updated disappearing messages "
            @"expiration to {{5 minutes}}'. See other *_TIME_AMOUNT strings");

        duration = durationSeconds / secondsPerMinute;
    } else if (durationSeconds < secondsPerHour * 1.5) { // 1 Hour
        amountFormat = NSLocalizedString(@"TIME_AMOUNT_SINGLE_HOUR",
            @"{{1 hour}} embedded in strings, e.g. 'Alice updated disappearing messages "
            @"expiration to {{1 hour}}'. See other *_TIME_AMOUNT strings");

        duration = durationSeconds / secondsPerHour;
    } else if (durationSeconds < secondsPerDay) { // Multiple Hours
        amountFormat = NSLocalizedString(@"TIME_AMOUNT_HOURS",
            @"{{number of hours}} embedded in strings, e.g. 'Alice updated disappearing messages "
            @"expiration to {{5 hours}}'. See other *_TIME_AMOUNT strings");

        duration = durationSeconds / secondsPerHour;
    } else if (durationSeconds < secondsPerDay * 1.5) { // 1 Day
        amountFormat = NSLocalizedString(@"TIME_AMOUNT_SINGLE_DAY",
            @"{{1 day}} embedded in strings, e.g. 'Alice updated disappearing messages "
            @"expiration to {{1 day}}'. See other *_TIME_AMOUNT strings");

        duration = durationSeconds / secondsPerDay;
    } else if (durationSeconds < secondsPerWeek) { // Multiple Days
        amountFormat = NSLocalizedString(@"TIME_AMOUNT_DAYS",
            @"{{number of days}} embedded in strings, e.g. 'Alice updated disappearing messages "
            @"expiration to {{5 days}}'. See other *_TIME_AMOUNT strings");

        duration = durationSeconds / secondsPerDay;
    } else if (durationSeconds < secondsPerWeek * 1.5) { // 1 Week
        amountFormat = NSLocalizedString(@"TIME_AMOUNT_SINGLE_WEEK",
            @"{{1 week}} embedded in strings, e.g. 'Alice updated disappearing messages "
            @"expiration to {{1 week}}'. See other *_TIME_AMOUNT strings");

        duration = durationSeconds / secondsPerWeek;
    } else { // Multiple weeks
        amountFormat = NSLocalizedString(@"TIME_AMOUNT_WEEKS",
            @"{{number of weeks}}, embedded in strings, e.g. 'Alice updated disappearing messages "
            @"expiration to {{5 weeks}}'. See other *_TIME_AMOUNT strings");

        duration = durationSeconds / secondsPerWeek;
    }

    return [NSString stringWithFormat:amountFormat, [NSNumberFormatter localizedStringFromNumber:@(duration)
                                                                                     numberStyle:NSNumberFormatterNoStyle]];
}

+ (NSArray<NSNumber *> *)validDurationsSeconds
{
    return @[ @(5),
              @(10),
              @(30),
              @(60),
              @(300),
              @(1800),
              @(3600),
              @(21600),
              @(43200),
              @(86400),
              @(604800) ];
}

- (NSUInteger)durationIndex
{
    return [[self.class validDurationsSeconds] indexOfObject:@(self.durationSeconds)];
}

- (NSString *)durationString
{
    return [self.class stringForDurationSeconds:self.durationSeconds];
}

#pragma mark - Dirty Tracking

+ (MTLPropertyStorage)storageBehaviorForPropertyWithKey:(NSString *)propertyKey
{
    // Don't persist transient properties
    if ([propertyKey isEqualToString:@"originalDictionaryValue"]
        ||[propertyKey isEqualToString:@"newRecord"]) {
        return MTLPropertyStorageNone;
    } else {
        return [super storageBehaviorForPropertyWithKey:propertyKey];
    }
}

- (BOOL)dictionaryValueDidChange
{
    return ![self.originalDictionaryValue isEqual:[self dictionaryValue]];
}

- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
    [super saveWithTransaction:transaction];
    self.originalDictionaryValue = [self dictionaryValue];
    self.newRecord = NO;
}

@end

NS_ASSUME_NONNULL_END
