﻿using Caliburn.Micro;
using Core.Models;
using TheChan.Services.Cache;
using System;
using Windows.Media.Core;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.System;
using FFmpegInterop;
using TheChan.Common;
using TheChan.Common.Core;
using TheChan.Services.Settings;
using Action = System.Action;

namespace TheChan.ViewModels {
    public class VideoPlayerViewModel : PropertyChangedBase {
        private bool canPlay;
        private bool isInProgress;
        private bool isError;
        private string status;
        private Uri uri;
        private IMediaSource source;

        public bool CanPlay {
            get { return this.canPlay; }
            private set {
                if (value == this.canPlay)
                    return;
                this.canPlay = value;
                NotifyOfPropertyChange();
            }
        }

        public bool IsInProgress {
            get { return this.isInProgress; }
            private set {
                if (value == this.isInProgress)
                    return;
                this.isInProgress = value;
                NotifyOfPropertyChange();
            }
        }

        public bool IsError {
            get { return this.isError; }
            private set {
                if (value == this.isError)
                    return;
                this.isError = value;
                NotifyOfPropertyChange();
            }
        }

        public string Status {
            get { return this.status; }
            private set {
                if (value == this.status)
                    return;
                this.status = value;
                NotifyOfPropertyChange();
            }
        }

        public Uri Uri {
            get { return this.uri; }
            private set {
                this.uri = value;
                NotifyOfPropertyChange();
            }
        }

        public IMediaSource Source {
            get { return this.source; }
            private set {
                if (Equals(value, this.source))
                    return;
                this.source = value;
                NotifyOfPropertyChange();
            }
        }

        public Action TryAgainAction { get; }
        private Attachment Attachment { get; }
        private WebmPlaybackMode WebmPlaybackMode { get; }

        private ICacheService CacheService { get; } = new CacheService();

        public VideoPlayerViewModel(Attachment attachment, WebmPlaybackMode webmPlaybackMode) {
            Attachment = attachment;
            WebmPlaybackMode = webmPlaybackMode;
            TryAgainAction = SetupNativePlayback;
            CanPlay = (WebmPlaybackMode == WebmPlaybackMode.Custom) ||
                      (WebmPlaybackMode == WebmPlaybackMode.Native && Utils.IsRedstone());


            if (!CanPlay)
                return;

            if (WebmPlaybackMode == WebmPlaybackMode.Custom) {
                SetupCustomPlayback();
            } else if (WebmPlaybackMode == WebmPlaybackMode.Native) {
                SetupNativePlayback();
            }
        }

        private async void SetupCustomPlayback() {
            IsInProgress = true;
            try {
                IRandomAccessStream stream = await CacheService.RetrieveStreamAsync(Attachment.Uri, CacheItemType.Video);
                FFmpegInteropMSS interop = FFmpegInteropMSS.CreateFFmpegInteropMSSFromStream(stream, true, true);
                MediaStreamSource mediaStreamSource = interop.GetMediaStreamSource();
                mediaStreamSource.BufferTime = new TimeSpan(0);
                Source = mediaStreamSource;
                IsInProgress = false;
            }
            catch {
                try {
                    await CacheService.DeleteItemAsync(Attachment.Uri);
                }
                catch { /* OK */ }
                IsInProgress = false;
                IsError = true;
                Status = Localization.GetForView("VideoPlayer", "Error");
            }
        }

        private void SetupNativePlayback() {
            Uri = new Uri(Attachment.Uri);
        }

        public async void OpenInPlayer() {
            IsInProgress = true;
            try {
                StorageFile file = await CacheService.RetrieveFileAsync(Attachment.Uri, CacheItemType.Video);
                IsInProgress = false;
                await Launcher.LaunchFileAsync(file);
            }
            catch {
                try {
                    await CacheService.DeleteItemAsync(Attachment.Uri);
                }
                catch { /* OK */ }
                IsInProgress = false;
                IsError = true;
                Status = Localization.GetForView("VideoPlayer", "Error");
            }
        }

        public async void OpenInBrowser() {
            await Launcher.LaunchUriAsync(new Uri(Attachment.Uri));
        }
    }
}