using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Realtime;
using Photon.Pun;

public class JobManager : MonoBehaviour, IInRoomCallbacks
{
    [Header("Data:")]
    [SerializeField] private List<JobTemplate> multiJobBonusTemplates = new List<JobTemplate>();
    [SerializeField] private List<JobTemplate> jobTemplates = new List<JobTemplate>();
    [SerializeField] private List<ZoneData> zones = new List<ZoneData>();
    [Header("Events:")]
    [SerializeField] private GameEvent onAvailableJobsUpdated;
    [SerializeField] private GameEvent_JobInstance onJobStarted;
    [SerializeField] private GameEvent_JobInstance onJobCompleted;
    [SerializeField] private GameEvent_JobInstance onSendMultiJobBonusRewards;
    [Header("Listeners:")]
    [SerializeField] private GameEventListener_JobInstance onJobSelectedLocally;
    [SerializeField] private GameEventListener onLoadLevelStarting;
    [SerializeField] private GameEventListener_ZoneData onGameSceneLoaded;
    [SerializeField] private GameEventListener onDifficultyChanged;
    [SerializeField] private GameEventListener onJoinedRoom;
    [SerializeField] private GameEventListener onBossDead;
    [SerializeField] private GameEventListener onMultiJobBonusRetrieved;

    [Header("Runtime Data:")]
    public bool JobActive = false;
    public JobInstance currentlySelectedJob;
    [SerializeField]
    public List<JobInstance> availableJobs = new List<JobInstance>();
    [SerializeField]
    public JobInstance multiJobBonus = new JobInstance();

    private string availableJobsJson;

    #region Singleton
    private static JobManager _instance;

    // Public reference to the singleton instance
    public static JobManager Instance
    {
        get
        {
            // If the instance doesn't exist, try to find it in the scene
            if (_instance == null)
            {
                _instance = FindObjectOfType<JobManager>();

                // If it's still null, create a new GameObject and add the component
                if (_instance == null)
                {
                    GameObject singletonObject = new GameObject(typeof(JobManager).Name);
                    _instance = singletonObject.AddComponent<JobManager>();
                }
            }
            return _instance;
        }
    }
    #endregion


    protected void Awake()
    {
        // Ensure there's only one instance
        if (_instance != null && _instance != this)
        {
            Destroy(gameObject);
            return;
        }

        // If this is the first instance, set it as the singleton
        _instance = this;
        DontDestroyOnLoad(gameObject);

        SetupEvents();
    }

    private void SetupEvents()
    {
        onJobSelectedLocally.Response.AddListener(UpdateJobSelection);
        onLoadLevelStarting.Response.AddListener(UpdateActiveJobState);
        onGameSceneLoaded.Response.AddListener(HandleGameSceneChanged);
        onDifficultyChanged.Response.AddListener(UpdateAvailableJobsRewardsOnDifficultyChanged);
        onDifficultyChanged.Response.AddListener(UpdateMultiJobBonusBasedOnDifficulty);
        onJoinedRoom.Response.AddListener(GenerateJobs);
        onBossDead.Response.AddListener(CompleteCurrentJob);
        onMultiJobBonusRetrieved.Response.AddListener(SendMultiJobBonusRewards);
    }

    public void UpdateJobSelection(JobInstance jobInstance)
    {
        currentlySelectedJob = jobInstance;
    }

    private void UpdateActiveJobState()
    {
        if (currentlySelectedJob.isHostileZone)
            JobActive = true;
    }

    private void HandleGameSceneChanged(ZoneData zoneData)
    {
        if (JobActive)
            onJobStarted.Raise(currentlySelectedJob);
    }

    public void CompleteCurrentJob()
    {
        if (!JobActive) return;

        if (!currentlySelectedJob.isHostileZone) return;

        onJobCompleted.Raise(currentlySelectedJob);
        JobActive = false;
        currentlySelectedJob.completed = true;

        if (!PhotonNetwork.IsMasterClient) return;

        UpdatePropertiesWithJobs();

        onAvailableJobsUpdated.Raise();

    }

    public void SendMultiJobBonusRewards()
    {
        //onSendMultiJobBonusRewards.Raise(multiJobBonus);
        onJobCompleted.Raise(multiJobBonus);
    }

    public JobInstance GenerateJobInstance(ZoneData respectiveZone)
    {
        List<JobTemplate> possibleTemplates = jobTemplates.FindAll(job => job.zoneName == respectiveZone.zoneName);
        JobTemplate usedTemplate = possibleTemplates[Random.Range(0, possibleTemplates.Count)];

        JobInstance generatedJob = new JobInstance(usedTemplate);
        generatedJob.templateIndex = jobTemplates.IndexOf(usedTemplate);

        generatedJob.UpdateRewardsBasedOnTemplateAndDifficulty(usedTemplate);

        return generatedJob;
    }
    private JobInstance GenerateMultiJobBonus(JobTemplate template)
    {
        JobInstance generatedBonus = new JobInstance(template);
        generatedBonus.UpdateRewardsBasedOnTemplateAndDifficulty(template);
        generatedBonus.templateIndex = multiJobBonusTemplates.IndexOf(template);
        return generatedBonus;
    }
    private void UpdateMultiJobBonusBasedOnDifficulty()
    {
        multiJobBonus.UpdateRewardsBasedOnTemplateAndDifficulty(multiJobBonusTemplates[multiJobBonus.templateIndex]);
    }

    private void UpdateAvailableJobsRewardsOnDifficultyChanged()
    {
        foreach (JobInstance job in availableJobs)
        {
            job.UpdateRewardsBasedOnTemplateAndDifficulty(jobTemplates[job.templateIndex]);
        }
    }

    public void GenerateJobs()
    {
        GenerateMultiJobBonus(multiJobBonusTemplates[0]);

        if (!PhotonNetwork.IsMasterClient)
        {
            TryGetAvailableJobsFromRoomProperties();
            return;
        }
        for (int i = 0; i < zones.Count; i++)
        {
            availableJobs.Add(GenerateJobInstance(zones[i]));
        }

        UpdatePropertiesWithJobs();

        onAvailableJobsUpdated.Raise();
    }

    private void UpdatePropertiesWithJobs()
    {
        if (availableJobs.TrueForAll(job => (job.isHostileZone && job.completed) || !job.isHostileZone))
        {
            availableJobs.Clear();
            Debug.Log("Jobs: Refreshing job state on all completed");
            GenerateJobs();
        }

        AvailableJobs jobs = new AvailableJobs();
        jobs.availableJobs = availableJobs;
        availableJobsJson = JsonUtility.ToJson(jobs);
        Debug.Log("Room Property jobs: " + availableJobsJson);
        ExitGames.Client.Photon.Hashtable ht = new ExitGames.Client.Photon.Hashtable { { GameConstants.NetworkPropertyKeys.AvailableJobsKey, availableJobsJson } };
        PhotonNetwork.CurrentRoom.SetCustomProperties(ht);
    }

    private void TryGetAvailableJobsFromRoomProperties()
    {
        ExitGames.Client.Photon.Hashtable roomProperties = PhotonNetwork.CurrentRoom.CustomProperties;
        if (roomProperties.ContainsKey(GameConstants.NetworkPropertyKeys.AvailableJobsKey))
        {
            availableJobsJson = (string)roomProperties[GameConstants.NetworkPropertyKeys.AvailableJobsKey];
            Debug.Log("Room Property Jobs: " + availableJobsJson);
            AvailableJobs jobs = JsonUtility.FromJson<AvailableJobs>(availableJobsJson);
            availableJobs = jobs.availableJobs;

            onAvailableJobsUpdated.Raise();
        }
    }

    public void OnRoomPropertiesUpdate(ExitGames.Client.Photon.Hashtable propertiesThatChanged)
    {
        if (PhotonNetwork.IsMasterClient) return;

        TryGetAvailableJobsFromRoomProperties();
    }



    public void OnPlayerEnteredRoom(Player newPlayer)
    {

    }

    public void OnPlayerLeftRoom(Player otherPlayer)
    {

    }

    public void OnPlayerPropertiesUpdate(Player targetPlayer, ExitGames.Client.Photon.Hashtable changedProps)
    {

    }

    public void OnMasterClientSwitched(Player newMasterClient)
    {

    }
}

[System.Serializable]
public class AvailableJobs
{
    public List<JobInstance> availableJobs = new List<JobInstance>();
}