using System;
using System.Collections.Generic;
using System.Linq;
using DG.Tweening;
using TMPro;
using UniRx;
using UnityEngine;
using UnityEngine.UI;

namespace DialogueSystem.Diary
{
    public class DiaryContentUI : MonoBehaviour
    {
        public DiaryDayScriptableObject currentDay;
        
        // Each day can have multiple pages, we keep track of the day AND the page number inside the day.
        public IntReactiveProperty currentPageInDay = new IntReactiveProperty(0);
        
        public Button nextPageButton;
        public Button previousPageButton;
        
        public TextMeshProUGUI headerText;
        public TextMeshProUGUI contentTextLeft;
        public TextMeshProUGUI contentTextRight;
        
        // Button Animation
        private Tween nextButtonTween;
        private Tween previousButtonTween;
        [Header("Animation")]
        public float moveDistance;
        public float moveDuration;

        public int wordCountToSplit;

        public bool ignoreDiaryScript = false;
        
        public void InstantiateTweens()
        {
            previousButtonTween = previousPageButton.transform.DOLocalMoveX(
                    previousPageButton.transform.localPosition.x + moveDistance, moveDuration)
                .SetLoops(-1, LoopType.Yoyo)
                .SetEase(Ease.InOutSine)
                .SetAutoKill(false)
                .SetUpdate(true);
    
            nextButtonTween = nextPageButton.transform.DOLocalMoveX(
                    nextPageButton.transform.localPosition.x + moveDistance, moveDuration)
                .SetLoops(-1, LoopType.Yoyo)
                .SetEase(Ease.InOutSine)
                .SetAutoKill(false)
                .SetUpdate(true);
        }
        
        private void OnEnable()
        {
            if (ignoreDiaryScript)
                return;
            
            nextPageButton.onClick.AddListener(GoToNextPage);
            previousPageButton.onClick.AddListener(GoToPreviousPage);    
            
            nextButtonTween.Restart();
            previousButtonTween.Pause();

            currentDay = DiaryManager.Instance.diaryDaysToShow[0];

            headerText.text = currentDay.headerText;
            
            if (currentDay.contentTexts.Count > 1)
            {
                EnableNextAndPreviousButton();
                currentPageInDay.Value = 0;
                previousPageButton.interactable = false;
                SetInputTextOnCanvas(currentDay.contentTexts[0]);
            }
            else
            {
                if (DiaryManager.Instance.diaryDaysToShow.Count > 1)
                {
                    EnableNextAndPreviousButton();
                    currentPageInDay.Value = 0;
                    previousPageButton.interactable = false;
                    SetInputTextOnCanvas(currentDay.contentTexts[0]);
                }
                else
                {
                    DisableNextAndPreviousButton();
                }
            }
            
        }

        private void GoToNextPage()
        {
            // Check if we reached the end of the day
            if (currentPageInDay.Value == currentDay.contentTexts.Count - 1)
            {
                // Go to next day
                OnDayEndReached();
                headerText.text = currentDay.headerText;
            }
            else
            {
                // Go to next page in the same day
                ++currentPageInDay.Value;
                SetInputTextOnCanvas(currentDay.contentTexts[currentPageInDay.Value]);
                UpdateButtonStates();
            }
        }

        private void OnDayEndReached()
        {
            // Check if there is another day, if so then go to the next one
            if (!DiaryManager.Instance.ReachedLastDayInDiary())
            {
                var currentDayNumber = ++DiaryManager.Instance.currentDayNumber.Value;
                var nextDay = DiaryManager.Instance.diaryDaysToShow[currentDayNumber];
                
                currentDay = nextDay;
                currentPageInDay.Value = 0;
                
                var textToInsert = currentDay.contentTexts[currentPageInDay.Value];
                SetInputTextOnCanvas(textToInsert);
                UpdateButtonStates();
            }
        }

        private void GoToPreviousPage()
        {
            // Check if we're on the first page of the current day
            if (currentPageInDay.Value == 0)
            {
                // Go to previous day
                OnDayStartReached();
                headerText.text = currentDay.headerText;
            }
            else
            {
                // Go to previous page in the same day
                --currentPageInDay.Value;
                SetInputTextOnCanvas(currentDay.contentTexts[currentPageInDay.Value]);
                UpdateButtonStates();
            }
        }

        private void OnDayStartReached()
        {
            // Check if there is a previous day
            if (DiaryManager.Instance.currentDayNumber.Value > 0)
            {
                var currentDayNumber = --DiaryManager.Instance.currentDayNumber.Value;
                var previousDay = DiaryManager.Instance.diaryDaysToShow[currentDayNumber];
                currentDay = previousDay;
                
                headerText.text = currentDay.headerText;
                
                // Set to the last page of the previous day
                currentPageInDay.Value = currentDay.contentTexts.Count - 1;
                
                var textToInsert = currentDay.contentTexts[currentPageInDay.Value];
                SetInputTextOnCanvas(textToInsert);
                UpdateButtonStates();
            }
        }

        private void SetInputTextOnCanvas(string input)
        {
            contentTextLeft.text = SplitLargeText(input).first;
            contentTextRight.text = SplitLargeText(input).second;
        }

        private (string first, string second) SplitLargeText(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
                return (string.Empty, string.Empty);

            // Split into words by whitespace
            var words = input.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
            // null separator => all whitespace; RemoveEmptyEntries avoids empty "words"

            if (words.Length <= wordCountToSplit)
                return (input, string.Empty);

            var firstPartWords  = words.Take(wordCountToSplit);
            var secondPartWords = words.Skip(wordCountToSplit);

            string firstPart  = string.Join(" ", firstPartWords);
            string secondPart = string.Join(" ", secondPartWords);

            return (firstPart, secondPart);
        }
        
        private void UpdateButtonStates()
        {
            // Disable previous button if at the first page of the first day
            previousPageButton.interactable = !(DiaryManager.Instance.currentDayNumber.Value == 0 && currentPageInDay.Value == 0);
            
            // Disable next button if at the last page of the last day
            bool isLastDay = DiaryManager.Instance.ReachedLastDayInDiary();
            bool isLastPageOfDay = currentPageInDay.Value == currentDay.contentTexts.Count - 1;
            nextPageButton.interactable = !(isLastDay && isLastPageOfDay);
        }
        
        private void EnableNextAndPreviousButton()
        {
            nextPageButton.gameObject.SetActive(true);
            previousPageButton.gameObject.SetActive(true);
        }

        private void DisableNextAndPreviousButton()
        {
            nextPageButton.gameObject.SetActive(false);
            previousPageButton.gameObject.SetActive(false);
        }

        private void OnDisable()
        {
            nextPageButton.onClick.RemoveListener(GoToNextPage);
            previousPageButton.onClick.RemoveListener(GoToPreviousPage);
        }
    }
}
