using System.IO;
using System.IO.IsolatedStorage;
using Java.Lang;
using Java.Security;
using Javax.Crypto;
using Android.OS;
using Bit.App.Abstractions;

namespace Bit.Android.Services
{
    public class KeyStoreStorageService : ISecureStorageService
    {
        private const string StorageFile = "Bit.Android.KeyStoreStorageService";

        private static readonly object SaveLock = new object();

        private readonly KeyStore _keyStore;
        private readonly KeyStore.PasswordProtection _protection;

        public KeyStoreStorageService()
            : this(Build.Serial.ToCharArray()) { }

        public KeyStoreStorageService(char[] password)
        {
            _keyStore = KeyStore.GetInstance(KeyStore.DefaultType);
            _protection = new KeyStore.PasswordProtection(password);

            if(File.FileExists(StorageFile))
            {
                using(var stream = new IsolatedStorageFileStream(StorageFile, FileMode.Open, FileAccess.Read, File))
                {
                    _keyStore.Load(stream, password);
                }
            }
            else
            {
                _keyStore.Load(null, password);
            }
        }

        private static IsolatedStorageFile File
        {
            get { return IsolatedStorageFile.GetUserStoreForApplication(); }
        }

        public void Store(string key, byte[] dataBytes)
        {
            _keyStore.SetEntry(key, new KeyStore.SecretKeyEntry(new SecureData(dataBytes)), _protection);
            Save();
        }

        public byte[] Retrieve(string key)
        {
            var entry = _keyStore.GetEntry(key, _protection) as KeyStore.SecretKeyEntry;
            if(entry == null)
            {
                return null;
            }

            return entry.SecretKey.GetEncoded();
        }

        public void Delete(string key)
        {
            _keyStore.DeleteEntry(key);
            Save();
        }

        public bool Contains(string key)
        {
            return _keyStore.ContainsAlias(key);
        }

        private void Save()
        {
            lock(SaveLock)
            {
                using(var stream = new IsolatedStorageFileStream(StorageFile, FileMode.OpenOrCreate, FileAccess.Write, File))
                {
                    _keyStore.Store(stream, _protection.GetPassword());
                }
            }
        }

        private class SecureData : Object, ISecretKey
        {
            private const string Raw = "RAW";

            private readonly byte[] _data;

            public SecureData(byte[] dataBytes)
            {
                _data = dataBytes;
            }

            public string Algorithm
            {
                get { return Raw; }
            }

            public string Format
            {
                get { return Raw; }
            }

            public byte[] GetEncoded()
            {
                return _data;
            }
        }
    }
}