using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using AppsFlyerSDK;
using System.Threading.Tasks;
using System;

public class AFDeepLinkHelper : MonoBehaviour, IAppsFlyerConversionData, IAppsFlyerUserInvite
{
    public bool DidReceivedDeepLink {get; private set;} // marks if we got a DL and processed it
    private Dictionary<string, object> _conversionDataDictionary;
    private Dictionary<string, object> _deepLinkParamsDictionary;

    public bool IsFirstLaunch {get ; private set;}
    public string AFState {get ; private set;}
    public IReadOnlyDictionary<string, object> DeepLinkParamsDictionary => _deepLinkParamsDictionary;
    public IReadOnlyDictionary<string, object> ConversionDataDictionary => _conversionDataDictionary;
    public string AttributionData {get; private set;}

    private string _referrerUID;
    private string _inviteLink;
    private TaskCompletionSource<string> _tcs; 
    public string StoreLink {get; private set;}

    public bool GetDLReferer(out string pid, out string uid)
    {
        pid = null;
        uid = null;

        if(!DidReceivedDeepLink)
            return false;
        if(_deepLinkParamsDictionary == null)
            return false;

        if(_deepLinkParamsDictionary.TryGetValue("deep_link_value", out var deep_link_value))
        {
            if((string)deep_link_value != "friend_invite")
                return false;

            if(_deepLinkParamsDictionary.TryGetValue("deep_link_sub2", out var referrer_pid))
                pid = (string)referrer_pid;
            if(_deepLinkParamsDictionary.TryGetValue("deep_link_sub1", out var referrer_uid))
                uid = (string)referrer_uid;

            if(!string.IsNullOrEmpty(pid) && !string.IsNullOrEmpty(uid))
                return true;
        }
        return false;
    }

    public static AFDeepLinkHelper Instance {get; private set;}

    public void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(this);
        }
        else
        {
            Instance = this;
        }
    }

    public void Init(string afkey, string afAppID, string customerUserID, string oneLinkID, bool debugMode = false)
    {
        AppsFlyer.setIsDebug(debugMode);
        AppsFlyer.setAppInviteOneLinkID(oneLinkID);
        AppsFlyer.initSDK(afkey, afAppID, this);
        AppsFlyer.setCustomerUserId(customerUserID);
        AppsFlyer.OnDeepLinkReceived += OnDeepLink;

#if UNITY_IOS
        AppsFlyerSDK.AppsFlyer.waitForATTUserAuthorizationWithTimeoutInterval(30);
#endif

        AppsFlyer.startSDK();
        AppsFlyerSDK.AppsFlyerAdRevenue.start();
    }

    public async Task<string> GenInviteLink(string referrerUID, string referrerPID)
    {
        if(referrerUID == _referrerUID && !string.IsNullOrEmpty(_inviteLink))
            return _inviteLink;
        _inviteLink = string.Empty;
        Dictionary<string, string> parameters = new Dictionary<string, string>();
        parameters.Add("channel", "mobile_share");
        parameters.Add("campaign", "friend_invite");

        parameters.Add("deep_link_value", "friend_invite");
        parameters.Add("deep_link_sub1", referrerUID);
        parameters.Add("deep_link_sub2", referrerPID);
        // Optional; makes the referrer ID available in the installs raw-data report
        parameters.Add("af_sub1", referrerPID);

        _tcs = new TaskCompletionSource<string>();
        AppsFlyer.generateUserInviteLink(parameters, this);
        _inviteLink = await _tcs.Task;
        return _inviteLink;
    }

    #region Implement IAppsFlyerConversionData

    public void onConversionDataSuccess(string conversionData)
    {
        Debug.Log("[AFDeepLinkHelper::didReceiveConversionData] success" );
        Dictionary<string, object> conversionDataDictionary = AppsFlyer.CallbackStringToDictionary(conversionData);
        _conversionDataDictionary = conversionDataDictionary;

        // af_status and is_first_launch always received with onConversionDataSuccess, no need to check if the keys exist
        AFState = _conversionDataDictionary["af_status"].ToString();
        IsFirstLaunch = (bool)_conversionDataDictionary["is_first_launch"];
    }

    public void onConversionDataFail(string error)
    {
        Debug.LogWarning("[AFDeepLinkHelper::didReceiveConversionData] error: " + error);
        _conversionDataDictionary = null;
    }

    public void onAppOpenAttribution(string attributionData)
    {
        Debug.Log("[AFDeepLinkHelper::onAppOpenAttribution] " + attributionData);
        AttributionData = attributionData;  
    }

    public void onAppOpenAttributionFailure(string error)
    {
        Debug.LogWarning("[AFDeepLinkHelper::onAppOpenAttributionFailure] error: " + error);
        AttributionData = null;
    }

    #endregion // Implement IAppsFlyerConversionData

    #region Implement IAppsFlyerUserInvite

    public void onInviteLinkGenerated(string link)
    {
        if(_tcs != null)
        {
            _tcs.SetResult(link);
        }
    }

    public void onInviteLinkGeneratedFailure(string error)
    {
        if(_tcs != null)
        {
            _tcs.SetResult(string.Empty);
        }
    }

    public void onOpenStoreLinkGenerated(string link)
    {
        Debug.Log("[AFDeepLinkHelper::onOpenStoreLinkGenerated] " + link);
        StoreLink = link;
    }

    #endregion // Implement IAppsFlyerUserInvite


    #region Deeplink 

    /** All the DeepLink handling has to be done under the onDeepLink handler **/
    void OnDeepLink(object sender, EventArgs args)
    {
        if (!(args is DeepLinkEventsArgs deepLinkEventArgs)) return;

        Debug.Log($"[AFDeepLinkHelper::onDeepLink] DeepLink Status {deepLinkEventArgs.status.ToString()}");

        switch (deepLinkEventArgs.status)
        {
            case DeepLinkStatus.FOUND:

                DidReceivedDeepLink = true;

                if (deepLinkEventArgs.isDeferred())
                {
                    Debug.Log($"[AFDeepLinkHelper::onDeepLink] DeepLink is deferred");
                }
                else
                {
                    Debug.Log($"[AFDeepLinkHelper::onDeepLink] This is a direct deep link");
                }
                _deepLinkParamsDictionary = GetDeepLinkParamsDictionary(deepLinkEventArgs);
                break;

            case DeepLinkStatus.NOT_FOUND:
                Debug.Log($"[AFDeepLinkHelper::onDeepLink] DeepLink not found");
                break;
            default:
                Debug.LogWarning($"[AFDeepLinkHelper::onDeepLink] DeepLink error");
                break;
        }
    }

    /** Get the DeepLink params depending on the device OS **/
    private Dictionary<string, object> GetDeepLinkParamsDictionary(DeepLinkEventsArgs deepLinkEventArgs)
    {
#if UNITY_IOS && !UNITY_EDITOR
    if (deepLinkEventArgs.deepLink.ContainsKey("click_event") && deepLinkEventArgs.deepLink["click_event"] != null)
    {
        return deepLinkEventArgs.deepLink["click_event"] as Dictionary<string, object>;
    }
#elif UNITY_ANDROID && !UNITY_EDITOR
    return deepLinkEventArgs.deepLink;
#endif

        return null;
    }

    #endregion // Deeplink
}
