//
//  ICRUserUtil.m
//  XFFruit
//
//  Created by Xummer on 3/29/15.
//  Copyright (c) 2015 Xummer. All rights reserved.
//

#import "ICRUserUtil.h"
#import "SSKeychain.h"
#import "SSKeychainQuery.h"
#import <objc/runtime.h>

#define kSchemePrefix               @"Keychain_"
#define kArchiveName                @"ICRLocalInfo"

NSString *const kSSKeychainPasswordKey = @"password";
NSString *const kSSKeychainUniqueIdentifierKey = @"uniqueIdentifier";

static ICRUserUtil *sharedInstance = nil;

@interface ICRUserUtil ()

@property (copy, nonatomic) NSString *uniqueIdentifier;

@end

@implementation ICRUserUtil

+ (instancetype)sharedInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self class] unarchive];
    });
    return sharedInstance;
}

+ (id)allocWithZone:(NSZone *)zone {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
            return sharedInstance;
        }
    }
    return nil;
}

+ (id)unarchive {
    NSString *filePath = [[self class] archivePath];
    
    ICRUserUtil *archive = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    if (archive == nil) {
        archive = [[[self class] alloc] init];
    }
    
    return archive;
}

- (id)init {
    if (self = [super init]) {
        self.userName = @"";
        self.password = @"";
        self.registerCode = @"";
        self.uniqueIdentifier = @"";
        self.token = @"";
        self.currentStoreID = @"";
        
        [self saveArchive];
    }
    
    return self;
}

- (BOOL)saveArchive {
    BOOL result;
    
    // get archive path to storage
    NSString *filePath = [[self class] archivePath];
    
    result = [NSKeyedArchiver archiveRootObject:self toFile:filePath];
    
    if (result) {
        // Save password in keychain
        if ([_userName length] > 0 && [_password length] > 0) {
            [self saveAuthorizeDataToKeychain];
        }
    }
    
    return result;
}

#pragma mark - Getter
- (NSString *)uniqueID {
    if (_uniqueID) {
        return _uniqueID;
    }
    else {
        self.uniqueID = [[[NSProcessInfo processInfo] globallyUniqueString] substringToIndex:15];
        [self saveArchive];
        
        return _uniqueID;
    }
}

- (NSString *)mobileID {
     NSString *uniqID15B = self.uniqueID;
    if(_uniqueID.length > 15)
    {
        uniqID15B = [uniqID15B substringToIndex:15];
    }
    NSString *date15B = [[NSDate date] mobileIDDateString];
    NSString *radom6B = [NSString stringWithFormat:@"%@", @( arc4random()%100000 + 100000 )];
    return [NSString stringWithFormat:@"%@%@%@", uniqID15B, date15B, radom6B];
}

#pragma mark - Public Method
- (BOOL)isLogin {
    return self.token.length > 0;
}

- (void)logout {
    if ([_userName length] > 0) {
        [self deleteAuthorizeDataInKeychain];
    }
    
    self.password = nil;
    self.token = nil;
    self.bAutoLogin = @( NO );
    self.currentStoreID = @"";
    
    [self saveArchive];
}

- (void)storageUserName:(NSString *)userName
               password:(NSString *)password
           registerCode:(NSString *)registerCode
                  token:(NSString *)token {
    self.userName = userName;
    self.password = password;
    self.registerCode = registerCode;
    self.token = token;
    
    [self saveArchive];
}

- (void)storageCurrentStoreID:(NSString *)currentStoreID {
    self.currentStoreID = currentStoreID;
    [self saveArchive];
}

- (void)updatePassword:(NSString *)pwd
{
    if ([self isLogin]) {
        self.password = pwd;
        
        [self saveUniqueIdentifierToKeychain];
    }
}
#pragma mark - Utilities

+ (NSString *)archivePath {
    NSString *archiveName = [[kArchiveName stringByDeletingPathExtension]
                             stringByAppendingPathExtension:@"archive"];
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    NSURL *baseURL = [fileManager URLForDirectory:NSApplicationSupportDirectory
                                         inDomain:NSUserDomainMask
                                appropriateForURL:nil
                                           create:YES
                                            error:NULL];
    
    return [[baseURL path] stringByAppendingPathComponent:archiveName];
}

- (NSString *)urlSchemeString {
    NSDictionary *infoDict =[[NSBundle mainBundle] infoDictionary];
    NSString *appName =[infoDict objectForKey:@"CFBundleDisplayName"];
    
    return [NSString stringWithFormat:@"%@%@_", kSchemePrefix, appName];
}

- (void)fetchAuthorizeDataFromKeychain {
    NSString *serviceName = [[self urlSchemeString] stringByAppendingString:_userName];
    
    self.password = [SSKeychain passwordForService:serviceName account:kSSKeychainPasswordKey];
}

- (void)saveAuthorizeDataToKeychain {
    NSString *serviceName = [[self urlSchemeString] stringByAppendingString:_userName];
    
    [SSKeychain setPassword:_password forService:serviceName account:kSSKeychainPasswordKey];
}

- (void)deleteAuthorizeDataInKeychain {
    NSString *serviceName = [[self urlSchemeString] stringByAppendingString:_userName];
    
    [SSKeychain deletePasswordForService:serviceName account:kSSKeychainPasswordKey];
}

- (void)fetchUniqueIdentifierFromKeychain {
    NSString *serviceName = [[self urlSchemeString] stringByAppendingString:kSSKeychainUniqueIdentifierKey];
    
    self.uniqueIdentifier = [SSKeychain passwordForService:serviceName account:kSSKeychainUniqueIdentifierKey];
}

- (void)saveUniqueIdentifierToKeychain {
    NSString *serviceName = [[self urlSchemeString] stringByAppendingString:kSSKeychainUniqueIdentifierKey];
    
    [SSKeychain setPassword:_uniqueIdentifier forService:serviceName account:kSSKeychainUniqueIdentifierKey];
}

- (void)deleteUniqueIdentifierToKeychain {
    NSString *serviceName = [[self urlSchemeString] stringByAppendingString:kSSKeychainUniqueIdentifierKey];
    
    [SSKeychain deletePasswordForService:serviceName account:kSSKeychainUniqueIdentifierKey];
}

#pragma mark - NSCoding
- (id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if (!self) {
        return self;
    }
    unsigned int count;
    objc_property_t *properties =
    class_copyPropertyList([self class], &count); for (NSUInteger i = 0; i < count; i++) {
        objc_property_t property = properties[i];
        NSString *key = [NSString stringWithUTF8String:property_getName(property)];
        [self setValue:[decoder decodeObjectForKey:key] forKey:key];
    }
    free(properties);
    
    return self;
}

- (void)encodeWithCoder:(NSCoder *)coder {
    unsigned int count;
    objc_property_t *properties =
    class_copyPropertyList([self class], &count); for (NSUInteger i = 0; i < count; i++) {
        objc_property_t property = properties[i];
        NSString *key = [NSString stringWithUTF8String:property_getName(property)];
        [coder encodeObject:[self valueForKey:key] forKey:key];
    }
    free(properties);
}

#pragma mark - NSCopying protocol methods

- (id)copyWithZone:(NSZone *)zone {
    ICRUserUtil *copy = [[[self class] allocWithZone:zone] init];
    unsigned int count;
    objc_property_t *properties =
    class_copyPropertyList([self class], &count); for (NSUInteger i = 0; i < count; i++) {
        objc_property_t property = properties[i];
        NSString *key = [NSString stringWithUTF8String:property_getName(property)];
        [copy setValue:[self valueForKey:key] forKey:key];
    }
    free(properties);
    
    return copy;
}

@end
