﻿using PaintTracker.Core.DependencyInterfaces;
using PaintTracker.Core.Models;
using PaintTracker.Core.Services;
using System;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace PaintTracker.Core.ViewModels
{
    public class CloudProviderVM<T> : BindableBase
        where T : ICloudProvider
    {
        private T _cloudProvider;
        private ImportService _importService;
        private ExportService _exportService;
        private DialogService _dialogService;
        private bool _isCheckingCache;
        private bool _isLoggedIn;
        private ViewModelService _viewModelService;
        private bool _internetStatus;

        public CloudProviderMenuItemVM ExportItem { get; private set; }
        public CloudProviderMenuItemVM ImportItem { get; private set; }
        public CloudProviderMenuItemVM LogoutItem { get; private set; }
        public CloudProviderMenuItemVM LoginItem { get; private set; }

        public event EventHandler<bool> ProcessingChanged;

        public bool HasInternet
        {
            get { return _internetStatus; }
            set { SetProperty(ref _internetStatus, value); }
        }

        public bool IsLoggedIn
        {
            get { return _isLoggedIn; }
            set { SetProperty(ref _isLoggedIn, value); }
        }

        public bool IsCheckingCache
        {
            get { return _isCheckingCache; }
            set
            {
                SetProperty(ref _isCheckingCache, value);
            }
        }

        public string Logo
        {
            get
            {
                var prefix = _cloudProvider.Name.ToLower();
                return Device.OnPlatform(
                    iOS: "",
                    Android: prefix + ".xml",
                    WinPhone: "Assets/" + prefix + ".png");
            }
        }

        public string Name { get; }

        public CloudProviderVM(ViewModelService viewModelService, DialogService dialogService, IExternalMessageSender messageSender, ImportService importService, ExportService exportService, T cloudProvider) : base(messageSender)
        {
            _cloudProvider = cloudProvider;
            _exportService = exportService;
            _importService = importService;
            _dialogService = dialogService;
            _viewModelService = viewModelService;

            Name = _cloudProvider.Name;

            var importItem = new CloudProviderMenuItem("Import", async _ => await ImportAsync());
            var exportItem = new CloudProviderMenuItem("Export", async _ => await ExportAsync());
            var logoutItem = new CloudProviderMenuItem("Log out", _ => Logout());
            var loginItem = new CloudProviderMenuItem("Log in", async _ => await LoginAsync());

            ImportItem = _viewModelService.CreateVM<CloudProviderMenuItemVM, CloudProviderMenuItem>(importItem);
            ExportItem = _viewModelService.CreateVM<CloudProviderMenuItemVM, CloudProviderMenuItem>(exportItem);
            LogoutItem = _viewModelService.CreateVM<CloudProviderMenuItemVM, CloudProviderMenuItem>(logoutItem);
            LoginItem = _viewModelService.CreateVM<CloudProviderMenuItemVM, CloudProviderMenuItem>(loginItem);

            IsCheckingCache = true;
        }

        public async Task LoginAsync()
        {
            IsLoggedIn = await _cloudProvider.LoginAsync();
        }

        private void FinishedUpdating(object arg1)
        {
            OnPropertyChanged(nameof(IsLoggedIn));
        }

        public async Task HasValidCachedTokenAsync()
        {
            IsLoggedIn = await _cloudProvider.HasValidCachedTokenAsync();
            IsCheckingCache = false;
        }

        public async Task ImportAsync()
        {
            var confirmRes = await _dialogService.DisplayAlertAsync("Import Data?", "WARNING: This will delete all current data!");

            if (!confirmRes)
            {
                return;
            }

            ProcessingChanged?.Invoke(this, true);

            _dialogService.ShowProgressDialog(Name, "Importing...");
            var res = await _cloudProvider.ImportDataAsync();

            if (res.HasError)
            {
                _dialogService.HideProgressDialog();
                _dialogService.DisplayAlert("Error", res.ErrorData);
            }
            else if (res.IsDataMissing)
            {
                _dialogService.HideProgressDialog();
                _dialogService.DisplayAlert("Could not import", "No import data found.");
            }
            else
            {
                var details = await _importService.ImportDataAsync(res.VersionData, res.ImportData);
                _dialogService.HideProgressDialog();
                _dialogService.DisplayAlert("Import successful", $"Owned: {details.Owned}{Environment.NewLine}Wanted: {details.Wanted}");
            }

            ProcessingChanged?.Invoke(this, false);
        }

        public async Task ExportAsync()
        {
            var confirmRes = await _dialogService.DisplayAlertAsync("Export Data?", "WARNING: This will delete any previously exported data!");

            if (!confirmRes)
            {
                return;
            }

            ProcessingChanged?.Invoke(this, true);

            _dialogService.ShowProgressDialog(Name, "Exporting...");
            var versionData = _exportService.GetExportVersionData();
            var paintData = await _exportService.GetExportPaintDataAsync();
            var res = await _cloudProvider.ExportDataAsync(versionData, paintData);
            _dialogService.HideProgressDialog();

            if (res.HasError)
            {
                _dialogService.DisplayAlert("Error", res.ErrorData);
            }

            ProcessingChanged?.Invoke(this, false);
        }

        public void Logout()
        {
            _cloudProvider.Logout();
            IsLoggedIn = false;
        }
    }
}
