using System;
using System.Collections.Generic;
using System.Linq;
using UniRx;
using UnityEngine;
using UnityEngine.UI;

public class MissionManager : MonoBehaviour
{
    public static readonly string MissionDataTag = "MissionData";
    private static readonly string CallbackTag = "MissionManagerCallback";
    private static readonly string AchievedCallbackTag = "MissionManagerAchievedCallback";
    private static readonly string TimeFormat = "更新まで：{0}時間{1}分{2}秒";
    private static readonly int OpenTrigger = Animator.StringToHash("OpenTrigger");
    private static readonly int CloseTrigger = Animator.StringToHash("CloseTrigger");
    private static readonly int dailyMissionCompleteRewardCoin = 50;
    
    [SerializeField] private Animator backgroundAnimator;
    [SerializeField] private Button closeButton;
    [SerializeField] private MissionListView listView;
    [SerializeField] private Text timeLimitText;

    private int normalIndicateFlag;
    private int dailyIndicateFlag;
    private Action<bool> onAchieved;

    private void Start()
    {
        closeButton.OnClickAsObservable().Take(1).Subscribe(_ =>
        {
            LocalCacheManager.Remove(MissionDataTag);
            transform.SetLocalScale(0);
            backgroundAnimator.SetTrigger(CloseTrigger);
            this.CallWaitForSeconds(.25f, () =>
            {
                LocalCacheManager.Load<Action>(CallbackTag, null)?.Invoke();
                LocalCacheManager.Remove(CallbackTag);
                LocalCacheManager.Remove(AchievedCallbackTag);
                TransitionManager.Instance.UnloadScene(GameScenes.Mission);
            });
        }).AddTo(this);

        listView.SelectedTab.Subscribe(category =>
        {
            timeLimitText.gameObject.SetActive(category == MissionCategory.Daily);
        }).AddTo(this);

        onAchieved = LocalCacheManager.Load<Action<bool>>(AchievedCallbackTag, null);
        var gameData = GameDataManager.GameData;

        // デイリーカウントダウン
        var limitTime = gameData.GetDailyMissionLimitTime();
        if (limitTime.TotalSeconds > 0)
        {
            timeLimitText.text = String.Format(TimeFormat, limitTime.Hours, limitTime.Minutes, limitTime.Seconds);
        }
        else
        {
            timeLimitText.text = String.Format(TimeFormat, 0, 0, 0);
        }
        Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1f))
            .Select(x => gameData.GetDailyMissionLimitTime())
            .TakeWhile(x => x.TotalSeconds > 0)
            .Subscribe(x =>
            {
                timeLimitText.text = String.Format(TimeFormat, x.Hours, x.Minutes, x.Seconds);
            }).AddTo(this);

        // ミッション読み込み
        var missionList = SpreadsheetDataManager.Instance.GetBaseDataList<MissionData>(Const.MissionDataSheet);
        GenerateNormalMission(missionList);
        
        // dailyMission
        // コンプリートミッション
        MissionView completeMissionView;
        {
            var missionView = listView.AddDailyCompleteItemView();
            completeMissionView = missionView;
            var missionData = new MissionData()
            {
                count = gameData.dailyMissionIdArray.Length,
                reward = dailyMissionCompleteRewardCoin,
                text = "デイリーミッションを達成しよう",
                category = (int)MissionCategory.Daily,
            };
            var progressValue = gameData.dailyMissionAchievedIdArray.Length;
            missionView.SetData(missionData, progressValue);
            missionView.SetButtonActive(missionData.count <= progressValue);
            if (gameData.dailyMissionCompleted) // 達成済み
            {
                missionView.SetRewarded();
            }
            else if (missionData.count <= progressValue)
            {
                dailyIndicateFlag++;
            }
            
            // リワード獲得
            missionView.RewardButton.ThrottleFirst(TimeSpan.FromSeconds(1f)).Subscribe(_ =>
            {
                dailyIndicateFlag--;
                listView.SetIndicator(MissionCategory.Daily, dailyIndicateFlag > 0);
                LocalCacheManager.Save(MissionDataTag, (missionData, new Action(() =>
                {
                    GetDailyMissionCompleteReward();
                    missionView.SetRewarded();
                    // 達成ID保存
                    gameData.dailyMissionCompleted = true;
                    GameDataManager.SaveGameData();
                    onAchieved?.Invoke(normalIndicateFlag + dailyIndicateFlag > 0);
                })));
                TransitionManager.Instance.LoadSceneAdditive(GameScenes.MissionAchievement);
            }).AddTo(missionView);
        }
        foreach (var missionData in missionList.Where(data => gameData.dailyMissionIdArray.Contains(data.id)))
        {
            var missionView = listView.AddItemView(missionData);
            var progressValue = GetDailyProgressValue(missionData);
            missionView.SetData(missionData, progressValue);
            missionView.SetButtonActive(missionData.count <= progressValue);
            if (gameData.dailyMissionAchievedIdArray.Contains(missionData.id)) // 達成済み
            {
                missionView.SetRewarded();
            }
            else if (missionData.count <= progressValue)
            {
                dailyIndicateFlag++;
            }
            
            // リワード獲得
            missionView.RewardButton.ThrottleFirst(TimeSpan.FromSeconds(1f)).Subscribe(_ =>
            {
                dailyIndicateFlag--;
                listView.SetIndicator(MissionCategory.Daily, dailyIndicateFlag > 0);
                LocalCacheManager.Save(MissionDataTag, (missionData, new Action(() =>
                {
                    GetReward(missionData);
                    missionView.SetRewarded();
                    // 達成ID保存
                    gameData.dailyMissionAchievedIdArray = new List<int>(gameData.dailyMissionAchievedIdArray){missionData.id}.ToArray();
                    GameDataManager.SaveGameData();
                    completeMissionView.ChangeProgress(gameData.dailyMissionIdArray.Length, gameData.dailyMissionAchievedIdArray.Length);
                    completeMissionView.SetButtonActive(gameData.dailyMissionIdArray.Length <= gameData.dailyMissionAchievedIdArray.Length);
                    onAchieved?.Invoke(normalIndicateFlag + dailyIndicateFlag > 0);
                })));
                TransitionManager.Instance.LoadSceneAdditive(GameScenes.MissionAchievement);
            }).AddTo(missionView);
        }
        listView.SetTab(MissionCategory.Daily);
        listView.SetIndicator(MissionCategory.Daily, dailyIndicateFlag > 0);
    }

    private void GenerateNormalMission(List<MissionData> missionList)
    {
        // ミッション表示
        normalIndicateFlag = 0;
        var latestMissionList = missionList
            .Where(data => data.Category == MissionCategory.Normal && data.shopLevel <= GameDataManager.GameData.ViewedShopLevel)
            .GroupBy(data => data.Condition, (cond, list) =>
            {
                return list.FirstOrDefault(data => !GameDataManager.GameData.AchievedMission.Contains(data.id)) ?? list.Last();
            });
        latestMissionList = latestMissionList.Where(data => CheckAvailableMission(data, GameDataManager.GameData.MyRecipes));
        foreach (var missionData in latestMissionList)
        {
            var missionView = listView.AddItemView(missionData);
            var progressValue = GetProgressValue(missionData);
            missionView.SetData(missionData, progressValue);
            missionView.SetButtonActive(missionData.count <= progressValue);
            if (GameDataManager.GameData.AchievedMission.Contains(missionData.id)) // 達成済み
            {
                missionView.SetRewarded();
            }
            else if (missionData.count <= progressValue)
            {
                normalIndicateFlag++;
            }

            // リワード獲得
            missionView.RewardButton.ThrottleFirst(TimeSpan.FromSeconds(1f)).Subscribe(_ =>
            {
                normalIndicateFlag--;
                listView.SetIndicator(MissionCategory.Normal, normalIndicateFlag > 0);
                LocalCacheManager.Save(MissionDataTag, (missionData, new Action(() =>
                {
                    GetReward(missionData);
                    // 達成ID保存
                    GameDataManager.GameData.AchievedMission.Add(missionData.id);
                    GameDataManager.SaveGameData();
                    listView.ResetItemList(MissionCategory.Normal);
                    GenerateNormalMission(missionList);
                    onAchieved?.Invoke(normalIndicateFlag + dailyIndicateFlag > 0);
                })));
                TransitionManager.Instance.LoadSceneAdditive(GameScenes.MissionAchievement);
            }).AddTo(missionView);
        }
        listView.SetIndicator(MissionCategory.Normal, normalIndicateFlag > 0);
    }

    public static void ShowDialog(Action onClose = null, Action<bool> onAchieved = null)
    {
        LocalCacheManager.Save(CallbackTag, onClose);
        LocalCacheManager.Save(AchievedCallbackTag, onAchieved);
        TransitionManager.Instance.LoadSceneAdditive(GameScenes.Mission);
    }

    public static bool CheckAvailableMission(MissionData missionData, int[] myRecipe)
    {
        // 購入レシピなど所持判定
        switch (missionData.Condition)
        {
            case MissionCondition.NoriSoysourceSalesCount:
                return myRecipe.Contains(20);
            case MissionCondition.RareNoriSoysourceSalesCount:
                return myRecipe.Contains(20);
            case MissionCondition.SaltButterSalesCount:
                return myRecipe.Contains(21);
            case MissionCondition.RareSaltButterSalesCount:
                return myRecipe.Contains(21);
            case MissionCondition.StrawberryMilkSalesCount:
                return myRecipe.Contains(22);
            case MissionCondition.RareStrawberryMilkSalesCount:
                return myRecipe.Contains(22);
            case MissionCondition.SaltChocolateSalesCount:
                return myRecipe.Contains(23);
            case MissionCondition.RareSaltChocolateSalesCount:
                return myRecipe.Contains(23);
            case MissionCondition.ChocolateGreenteaSalesCount:
                return myRecipe.Contains(24);
            case MissionCondition.RareChocolateGreenteaSalesCount:
                return myRecipe.Contains(24);
            default:
                return true;
        }
    }

    public static int GetProgressValue(MissionData missionData)
    {
        var gameData = GameDataManager.GameData;
        switch (missionData.Condition)
        {
            case MissionCondition.CornCount:
                return gameData.TotalAddCornSeed;
            case MissionCondition.CustomerCount: // タップor来客した数
                return gameData.TotalCustomerCount;
            case MissionCondition.SalesCount: // 売った数
                return gameData.TotalSales;
            case MissionCondition.RareSalesCount: // レアを売った数
                return gameData.RareTotalSales;
            case MissionCondition.RecipeCount: // レシピの数
                return gameData.MyRecipes.Length;
            case MissionCondition.CoinConsumeCount: // コイン消費数
                return gameData.TotalSubCoin;
            case MissionCondition.BulkOrderDeliveredCount:
                return gameData.BulkOrderDeliveredCount;
            case MissionCondition.SaltSalesCount:
                return gameData.GetTotalSalesByFlavor(1);
            case MissionCondition.RareSaltSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(1);
            case MissionCondition.CaramelSalesCount:
                return gameData.GetTotalSalesByFlavor(2);
            case MissionCondition.RareCaramelSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(2);
            case MissionCondition.PepperSalesCount:
                return gameData.GetTotalSalesByFlavor(3);
            case MissionCondition.RarePepperSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(3);
            case MissionCondition.HoneySalesCount:
                return gameData.GetTotalSalesByFlavor(4);
            case MissionCondition.RareHoneySalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(4);
            case MissionCondition.CheeseSalesCount:
                return gameData.GetTotalSalesByFlavor(5);
            case MissionCondition.RareCheeseSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(5);
            case MissionCondition.SoysourceSalesCount:
                return gameData.GetTotalSalesByFlavor(6);
            case MissionCondition.RareSoysourceSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(6);
            case MissionCondition.StrawberrySalesCount:
                return gameData.GetTotalSalesByFlavor(7);
            case MissionCondition.RareStrawberrySalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(7);
            case MissionCondition.GreenteaSalesCount:
                return gameData.GetTotalSalesByFlavor(8);
            case MissionCondition.RareGreenteaSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(8);
            case MissionCondition.ChocolateSalesCount:
                return gameData.GetTotalSalesByFlavor(9);
            case MissionCondition.RareChocolateSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(9);
            case MissionCondition.NoriSaltSalesCount:
                return gameData.GetTotalSalesByFlavor(10);
            case MissionCondition.RareNoriSaltSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(10);
            case MissionCondition.ButterSoysourceSalesCount:
                return gameData.GetTotalSalesByFlavor(11);
            case MissionCondition.RareButterSoysourceSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(11);
            case MissionCondition.PepperCheeseSalesCount:
                return gameData.GetTotalSalesByFlavor(12);
            case MissionCondition.RarePepperCheeseSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(12);
            case MissionCondition.SaltCaramelSalesCount:
                return gameData.GetTotalSalesByFlavor(13);
            case MissionCondition.RareSaltCaramelSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(13);
            case MissionCondition.NoriButterSalesCount:
                return gameData.GetTotalSalesByFlavor(14);
            case MissionCondition.RareNoriButterSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(14);
            case MissionCondition.MilkChocolateSalesCount:
                return gameData.GetTotalSalesByFlavor(15);
            case MissionCondition.RareMilkChocolateSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(15);
            case MissionCondition.CaramelCheeseSalesCount:
                return gameData.GetTotalSalesByFlavor(16);
            case MissionCondition.RareCaramelCheeseSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(16);
            case MissionCondition.HoneyButterSalesCount:
                return gameData.GetTotalSalesByFlavor(17);
            case MissionCondition.RareHoneyButterSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(17);
            case MissionCondition.GreenteaMilkSalesCount:
                return gameData.GetTotalSalesByFlavor(18);
            case MissionCondition.RareGreenteaMilkSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(18);
            case MissionCondition.StrawberryChocolaSalesCount:
                return gameData.GetTotalSalesByFlavor(19);
            case MissionCondition.RareStrawberryChocolateSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(19);
            case MissionCondition.NoriSoysourceSalesCount:
                return gameData.GetTotalSalesByFlavor(20);
            case MissionCondition.RareNoriSoysourceSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(20);
            case MissionCondition.SaltButterSalesCount:
                return gameData.GetTotalSalesByFlavor(21);
            case MissionCondition.RareSaltButterSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(21);
            case MissionCondition.StrawberryMilkSalesCount:
                return gameData.GetTotalSalesByFlavor(22);
            case MissionCondition.RareStrawberryMilkSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(22);
            case MissionCondition.SaltChocolateSalesCount:
                return gameData.GetTotalSalesByFlavor(23);
            case MissionCondition.RareSaltChocolateSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(23);
            case MissionCondition.ChocolateGreenteaSalesCount:
                return gameData.GetTotalSalesByFlavor(24);
            case MissionCondition.RareChocolateGreenteaSalesCount:
                return gameData.GetTotalSalesByFlavorWithRare(24);
            default:
                return 0;
        }
    }

    public static int GetDailyProgressValue(MissionData missionData)
    {
        var gameData = GameDataManager.GameData;
        switch (missionData.Condition)
        {
            case MissionCondition.CornCount:
                return gameData.DailyTotalAddCornSeed;
            case MissionCondition.CustomerCount: // タップor来客した数
                return gameData.DailyTotalCustomerCount;
            case MissionCondition.SalesCount: // 売った数
                return gameData.DailyTotalSales;
            case MissionCondition.RareSalesCount: // レアを売った数
                return gameData.DailyRareTotalSales;
            case MissionCondition.RecipeCount: // レシピの数
                return gameData.DailyRecipeGetCount;
            case MissionCondition.CoinConsumeCount: // コイン消費数
                return gameData.DailyTotalSubCoin;
            case MissionCondition.BulkOrderDeliveredCount:
                return gameData.DailyBulkOrderDeliveredCount;
            case MissionCondition.SaltSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(1);
            case MissionCondition.RareSaltSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(1);
            case MissionCondition.CaramelSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(2);
            case MissionCondition.RareCaramelSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(2);
            case MissionCondition.PepperSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(3);
            case MissionCondition.RarePepperSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(3);
            case MissionCondition.HoneySalesCount:
                return gameData.GetDailyTotalSalesByFlavor(4);
            case MissionCondition.RareHoneySalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(4);
            case MissionCondition.CheeseSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(5);
            case MissionCondition.RareCheeseSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(5);
            case MissionCondition.SoysourceSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(6);
            case MissionCondition.RareSoysourceSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(6);
            case MissionCondition.StrawberrySalesCount:
                return gameData.GetDailyTotalSalesByFlavor(7);
            case MissionCondition.RareStrawberrySalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(7);
            case MissionCondition.GreenteaSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(8);
            case MissionCondition.RareGreenteaSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(8);
            case MissionCondition.ChocolateSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(9);
            case MissionCondition.RareChocolateSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(9);
            case MissionCondition.NoriSaltSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(10);
            case MissionCondition.RareNoriSaltSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(10);
            case MissionCondition.ButterSoysourceSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(11);
            case MissionCondition.RareButterSoysourceSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(11);
            case MissionCondition.PepperCheeseSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(12);
            case MissionCondition.RarePepperCheeseSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(12);
            case MissionCondition.SaltCaramelSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(13);
            case MissionCondition.RareSaltCaramelSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(13);
            case MissionCondition.NoriButterSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(14);
            case MissionCondition.RareNoriButterSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(14);
            case MissionCondition.MilkChocolateSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(15);
            case MissionCondition.RareMilkChocolateSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(15);
            case MissionCondition.CaramelCheeseSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(16);
            case MissionCondition.RareCaramelCheeseSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(16);
            case MissionCondition.HoneyButterSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(17);
            case MissionCondition.RareHoneyButterSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(17);
            case MissionCondition.GreenteaMilkSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(18);
            case MissionCondition.RareGreenteaMilkSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(18);
            case MissionCondition.StrawberryChocolaSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(19);
            case MissionCondition.RareStrawberryChocolateSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(19);
            case MissionCondition.NoriSoysourceSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(20);
            case MissionCondition.RareNoriSoysourceSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(20);
            case MissionCondition.SaltButterSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(21);
            case MissionCondition.RareSaltButterSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(21);
            case MissionCondition.StrawberryMilkSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(22);
            case MissionCondition.RareStrawberryMilkSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(22);
            case MissionCondition.SaltChocolateSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(23);
            case MissionCondition.RareSaltChocolateSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(23);
            case MissionCondition.ChocolateGreenteaSalesCount:
                return gameData.GetDailyTotalSalesByFlavor(24);
            case MissionCondition.RareChocolateGreenteaSalesCount:
                return gameData.GetDailyTotalSalesByFlavorWithRare(24);
            default:
                return 0;
        }
    }

    private void GetReward(MissionData missionData)
    {
        if (missionData.RewardType == MissionRewardType.Coin)
        {
            CoinManager.Instance.AddCoinWithEffect(missionData.reward, () => {});
            GameDataManager.GameData.Coin = CoinManager.Instance.OwnCoin;
        }
    }

    private void GetDailyMissionCompleteReward()
    {
        CoinManager.Instance.AddCoinWithEffect(dailyMissionCompleteRewardCoin);
        GameDataManager.GameData.Coin = CoinManager.Instance.OwnCoin;
    }
}