﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using HIO_Backup.Interface;
using HIO_Backup.Model;
using HIO_Backup.Model.Enums;
using HIO_Backup.Destinations;
using HIO_Backup.Persistence.AppData;
using Alphaleonis.Win32.Filesystem;

namespace HIO_Backup.Persistence.Disk
{
    class BackupDestinationDiskProvider : BackupDestinationAppDataProvider
    {
        // - Extra properties
        private DestinationType Type;
        private string SelfFile;

        // - Constructor
        public async Task<BackupDestinationDiskProvider> InitializeAsync(ShareBackupDestinationInput self)
        {
            this.Type = DestinationType.NetworkShare;
            this.ConfigFolder = Path.Combine(self.UncPath, self.MachineName, "config");
            this.SelfFile = Path.Combine(this.ConfigFolder, "self.json");

            await this.InitializeAsyncCommon();

            if(await this.FileExistAsync(this.SelfFile))
            {
                await this.UpdateSelfAsync(self);
            }
            else
            {
                await this.AddSelfAsync(self);
            }

            return this;
        }

        public async Task<BackupDestinationDiskProvider> InitializeAsync(MountedBackupDestinationInput self)
        {
            string basePath = await MountedDestination.GetDrivePathAsync(self.VolumeName);

            this.Type = DestinationType.MountedDrive;
            this.ConfigFolder = Path.Combine(basePath, self.MachineName, "config");
            this.SelfFile = Path.Combine(this.ConfigFolder, "self.json");

            await this.InitializeAsyncCommon();

            if (await this.FileExistAsync(this.SelfFile))
            {
                await this.UpdateSelfAsync(self);
            }
            else
            {
                await this.AddSelfAsync(self);
            }

            return this;
        }

        public static async Task<BackupDestinationDiskProvider> CreateAsync(MountedBackupDestinationInput self)
        {
            BackupDestinationDiskProvider instance = new BackupDestinationDiskProvider();
            return await instance.InitializeAsync(self);
        }

        // - Add self
        private async Task AddSelfAsync(MountedBackupDestinationInput self)
        {
            await JsonSerialization.WriteToJsonFileAsync(this.SelfFile, self);
            await this.AddAsync(self);
        }

        private async Task AddSelfAsync(ShareBackupDestinationInput self)
        {
            await JsonSerialization.WriteToJsonFileAsync(this.SelfFile, self);
            await this.AddAsync(self);
        }

        // - Update self
        public async Task UpdateSelfAsync(MountedBackupDestinationInput self)
        {
            MountedBackupDestinationInput fromDisk = await JsonSerialization.ReadFromJsonFileAsync<MountedBackupDestinationInput>(this.SelfFile);
            if (!self.Equals(fromDisk))
            {
                await JsonSerialization.WriteToJsonFileAsync(this.SelfFile, self);
                await this.UpdateAsync(self);
            }
        }

        public async Task UpdateSelfAsync(ShareBackupDestinationInput self)
        {
            ShareBackupDestinationInput fromDisk = await JsonSerialization.ReadFromJsonFileAsync<ShareBackupDestinationInput>(this.SelfFile);
            if (!self.Equals(fromDisk))
            {
                await JsonSerialization.WriteToJsonFileAsync(this.SelfFile, self);
                await this.UpdateAsync(self);
            }
        }

        // - Get self id
        public async Task<Guid> GetSelfId()
        {
            if(this.Type == DestinationType.MountedDrive)
            {
                MountedBackupDestinationInput i = await JsonSerialization.ReadFromJsonFileAsync<MountedBackupDestinationInput>(this.SelfFile);
                return i.Id;
            }
            else
            {
                ShareBackupDestinationInput i = await JsonSerialization.ReadFromJsonFileAsync<ShareBackupDestinationInput>(this.SelfFile);
                return i.Id;
            }
        }
    }
}
