﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace BugseePlugin
{
    /// <summary>
    /// Contains options that help you configure the behavior of Bugsee.
    /// </summary>
    public class AndroidLaunchOptions : BugseeLaunchOptions
    {
        public AndroidLaunchOptions()
        {
            // Set defaults
            this.SetDefaults();
        }

        private void SetDefaults()
        {
            MaxRecordingTime = 60;
            ShakeToTrigger = true;
            NotificationBarTrigger = true;
            CrashReport = true;
            UseSdCard = true;
            VideoEnabled = IsVideoSupported();
            CaptureLogs = true;
            ExtendedVideoMode = true;
            MonitorNetwork = true;
            ServiceMode = false;
            LogLevel = BugseeLogLevel.Verbose;
            FrameRate = BugseeFrameRate.High;
            MaxDataSize = 50;
            ReportPrioritySelector = false;
            DefaultCrashPriority = BugseeSeverityLevel.Blocker;
            DefaultBugPriority = BugseeSeverityLevel.High;
            WifiOnlyUpload = false;

            // No concrete default value for ScreenshotEnabled, because it depends on VideoEnabled option value.
        }

        /// <summary>
        /// Reverts any changes and resets options to their defaults
        /// </summary>
        public override void Reset()
        {
            base.Reset();

            this.SetDefaults();
        }

        /// <summary>
        /// Returns new instance with all options set to default values
        /// </summary>
        /// <returns>The default options.</returns>
        public static BugseeLaunchOptions GetDefaultOptions()
        {
            return new AndroidLaunchOptions();
        }

        /// <summary>
        /// Maximum recording duration (in seconds)
        /// </summary>
        /// <value>The max recording time.</value>
        public int MaxRecordingTime
        {
            get { return (int)this["MaxRecordingTime"]; }
            set { this["MaxRecordingTime"] = value; }
        }

        /// <summary>
        /// Enables/diables shake gesture detection to trigger report
        /// </summary>
        /// <value><c>true</c> to enable; otherwise, <c>false</c>.</value>
        public bool ShakeToTrigger
        {
            get { return (bool)this["ShakeToTrigger"]; }
            set { this["ShakeToTrigger"] = value; }
        }

        /// <summary>
        /// Trigger report from notification bar
        /// </summary>
        /// <value><c>true</c> to enable; otherwise, <c>false</c>.</value>
        public bool NotificationBarTrigger
        {
            get { return (bool)this["NotificationBarTrigger"]; }
            set { this["NotificationBarTrigger"] = value; }
        }

        /// <summary>
        /// Catch and report application crashes
        /// </summary>
        /// <value><c>true</c> to enable; otherwise, <c>false</c>.</value>
        public bool CrashReport
        {
            get { return (bool)this["CrashReport"]; }
            set { this["CrashReport"] = value; }
        }

        /// <summary>
        /// By default Bugsee saves its data to SD card (if ServiceMode option is not enabled).
        /// When set to false, internal app storage will be used. If your app does not require
        /// external storage, you might want to disable it in production builds. 
        /// </summary>
        /// <value><c>true</c> to enable; otherwise, <c>false</c>.</value>
        public bool UseSdCard
        {
            get { return (bool)this["UseSdCard"]; }
            set { this["UseSdCard"] = value; }
        }

        /// <summary>
        /// Record video. If false, created issues will contain console logs, events and traces,
        /// but will not contain video.
        /// </summary>
        /// <value><c>true</c> to enable; otherwise, <c>false</c>.</value>
        public bool VideoEnabled
        {
            get { return (bool)this["VideoEnabled"]; }
            set { this["VideoEnabled"] = value && IsVideoSupported(); }
        }

        /// <summary>
        /// f true, MediaProjection API is used, while recording video. In this case all types of
        /// views are recorded, but user is asked to allow video recording. If false (experimental),
        /// view drawing cache is used to capture the screen. In this case user is not asked to
        /// allow video recording, but frame rate is lower and some special views like status bar,
        /// soft keyboard and views, which contain Surface (MapView, VideoView, GlSurfaceView, etc.)
        /// are not recorded. Option has no effect, if VideoEnabled option is set to false.
        /// </summary>
        /// <value><c>true</c> to enable; otherwise, <c>false</c>.</value>
        public bool ExtendedVideoMode
        {
            get { return (bool)this["ExtendedVideoMode"]; }
            set { this["ExtendedVideoMode"] = value; }
        }

        /// <summary>
        /// Monitor network events
        /// </summary>
        /// <value><c>true</c> enable; otherwise, <c>false</c>.</value>
        public bool MonitorNetwork
        {
            get { return (bool)this["MonitorNetwork"]; }
            set { this["MonitorNetwork"] = value; }
        }

        /// <summary>
        /// Should be used, when Bugsee is launched from service. If true, video is not recorded and
        /// recording is not stopped, when app goes to background; ShakeToTrigger and
        /// NotificationBarTrigger options are set to false automatically.
        /// </summary>
        /// <value><c>true</c> to enable; otherwise, <c>false</c>.</value>
        public bool ServiceMode
        {
            get { return (bool)this["ServiceMode"]; }
            set { this["ServiceMode"] = value; }
        }

        /// <summary>
        /// Minimal log level of Logcat messages, which will be attached to reports. Option has no effect 
        /// if CaptureLogs option is false. Option has value of BugseeLogLevel type.
        /// </summary>
        /// <value>The log level.</value>
        public BugseeLogLevel LogLevel
        {
            get { return (BugseeLogLevel)(int)this["LogLevel"]; }
            set { this["LogLevel"] = (int)value; }
        }

        /// <summary>
        /// Specifies how often frames are captured. <br/>
        /// </summary>
        /// <value>The frame rate.</value>
        public BugseeFrameRate FrameRate
        {
            get { return (BugseeFrameRate)(int)this["FrameRate"]; }
            set { this["FrameRate"] = (int)value; }
        }
        
        /// <summary>
        /// Allow user to modify priority when reporting manually
        /// </summary>
        /// <value><c>true</c> to enable; otherwise, <c>false</c>.</value>
        public bool ReportPrioritySelector
        {
            get { return (bool)this["BugseeReportPrioritySelector"]; }
            set { this["BugseeReportPrioritySelector"] = value; }
        }

        /// <summary>
        /// Default priority for crashes
        /// </summary>
        /// <value>The default crash priority.</value>
        public BugseeSeverityLevel DefaultCrashPriority
        {
            get { return (BugseeSeverityLevel)(int)this["BugseeDefaultCrashPriority"]; }
            set { this["BugseeDefaultCrashPriority"] = (int)value; }
        }

        /// <summary>
        /// Default priority for bugs
        /// </summary>
        /// <value>The default bug priority.</value>
        public BugseeSeverityLevel DefaultBugPriority
        {
            get { return (BugseeSeverityLevel)(int)this["BugseeDefaultBugPriority"]; }
            set { this["BugseeDefaultBugPriority"] = (int)value; }
        }
        
         /// <summary>
        /// Automatically capture Logcat logs
        /// </summary>
        /// <value><c>true</c> to enable; otherwise, <c>false</c>.</value>
        public bool CaptureLogs
        {
            get { return (bool)this["CaptureLogs"]; }
            set { this["CaptureLogs"] = value; }
        }
        
        /// <summary>
        /// Attach screenshot to a report.
        /// </summary>
        /// <value><c>true</c> to enable; otherwise, <c>false</c>.</value>
        public bool ScreenshotEnabled
        {
            get
            {
                var result = this["ScreenshotEnabled"];
                return (result == null) ? VideoEnabled : (bool)result;
            }
            set { this["ScreenshotEnabled"] = value; }
        }

        /// <summary>
        /// Upload reports only when a device is connected to a wifi network.
        /// </summary>
        /// <value><c>true</c> to enable; otherwise, <c>false</c>.</value>
        public bool WifiOnlyUpload
        {
            get { return (bool)this["WifiOnlyUpload"]; }
            set { this["WifiOnlyUpload"] = value; }
        }
        
        /// <summary>
        /// Bugsee will avoid using more disk space than specified (in MB). If total Bugsee data size exceeds
        /// specified value, oldest recordings (even not sent) will be removed. Value should not be smaller
        /// than 10.
        /// </summary>
        /// <value>The size of the max data.</value>
        public int MaxDataSize
        {
            get;
            set;
        }
        
#if UNITY_ANDROID && !UNITY_EDITOR
        private static AndroidJavaClass BuildClass = new AndroidJavaClass("android.os.Build");
        private static AndroidJavaClass BuildVersionClass = new AndroidJavaClass("android.os.Build$VERSION");
        
		// After sending several reports black screen is shown instead of Unity activity on Samsung Galaxy S6. It is supposed that wide variety of Samsung devices have this bug.  
        private static bool IsVideoSupported() 
        {
            String manufacturer = BuildClass.GetStatic<String>("MANUFACTURER");
            if (manufacturer == null)
                return true;
                
            //Debug.Log("manufacturer - " + manufacturer);
            int buildVersion = BuildVersionClass.GetStatic<int>("SDK_INT");  
            //Debug.Log("buildVersion - " + buildVersion);   
            return !("samsung".Equals(manufacturer.ToLowerInvariant()) && buildVersion > 22);      
        }
#else
        private static bool IsVideoSupported() 
        {
            return true;
        }
#endif
    }
}
