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

public class Build : MonoBehaviour {

    // add material system
    public BuildHandler buildHandler;
    public PhotonView photonView;

    List<BuiltBlock> builtBlocks;
    Dictionary<int, float> healthUpdate; // map of grid node indexes and their health
    Dictionary<int, float> grayScaleUpdates; // map of MaterialDrainValue scripts (their indexes) to their respective gray scale values

    float sendRate = 0.5f;
    float nextSendTime = 0.0f;

    void Start() {
        if(!buildHandler) {
            GameObject obj = GameObject.FindGameObjectWithTag("BuildHandler");
            if (obj) {
                buildHandler = obj.GetComponent<BuildHandler>();
            }
        }
        if(!photonView)
            photonView = GetComponent<PhotonView>();

        builtBlocks = new List<BuiltBlock>();
        healthUpdate = new Dictionary<int, float>();
        grayScaleUpdates = new Dictionary<int, float>();
    }

    void Update() {
        if (!buildHandler.UpdateBuildHandling()) {
            HandleNetworkUpdates();
            return;
        }
		if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.H)) {
            bool success = buildHandler.OnBuildInput();
            
            if (success) {
                // photon instantiate ?
                // network creation with node and rotation
                GridNode gridNode = buildHandler.GetGridNode();
                GridObject gridObject = buildHandler.GetCurrentBlock();

                BuiltBlock builtBlock = new BuiltBlock(gridNode.index, buildHandler.GetRotation(), gridObject.blockType);
                builtBlocks.Add(builtBlock);
                //if(photonView)
                //    photonView.RPC("CreateRemoteBuild", RpcTarget.OthersBuffered, gridNode.block.name);

                //Debug.Log(gridNode.block.name);
                //remove materials
            }
        }
        HandleNetworkUpdates();
    }

    void HandleNetworkUpdates() {
        if (!PhotonNetwork.IsConnected)
            return;

        if (Time.unscaledTime > nextSendTime) {
            nextSendTime = Time.unscaledTime + sendRate;
            if (builtBlocks.Count > 0 || healthUpdate.Count > 0 || grayScaleUpdates.Count > 0) {
                //string debugLine = "";

                int[] gridIndexes = new int[builtBlocks.Count];
                float[] gridRotations = new float[builtBlocks.Count];
                byte[] gridTypes = new byte[builtBlocks.Count];
                int[] gridObjectsDamagedIndexes = new int[healthUpdate.Count];
                float[] gridObjectsDamagedHealth = new float[healthUpdate.Count];

                int[] grayScaleIndexes = new int[grayScaleUpdates.Count];
                float[] grayScaleValues = new float[grayScaleUpdates.Count];

                for (int i = 0; i < builtBlocks.Count; i++) {
                    //debugLine = string.Format("index: {0}; rotation: {1:0}; type: {2}", builtBlocks[i].index, builtBlocks[i].rotation, builtBlocks[i].blockType);
                    //Debug.Log(debugLine);
                    gridIndexes[i] = builtBlocks[i].index;
                    gridRotations[i] = builtBlocks[i].rotation;
                    gridTypes[i] = (byte)builtBlocks[i].blockType;
                }

                int j = 0;
                foreach (KeyValuePair<int, float> update in healthUpdate) {
                    //debugLine = string.Format("index: {0}; health: {1:0};", update.Key, update.Value);
                    //Debug.LogError(debugLine);
                    gridObjectsDamagedIndexes[j] = update.Key;
                    gridObjectsDamagedHealth[j] = update.Value;
                    j++;
                }

                j = 0;
                foreach (KeyValuePair<int, float> update in grayScaleUpdates) {
                    //debugLine = string.Format("index: {0}; grayScale: {1};", update.Key, update.Value);
                    // Debug.LogError(debugLine);
                    grayScaleIndexes[j] = update.Key;
                    grayScaleValues[j] = update.Value;
                    j++;
                }

                PhotonDebugger.IncrementNumberOfMessages("build");
                photonView.RPC("NetworkBuiltObjects", RpcTarget.OthersBuffered, (object)gridIndexes, (object)gridRotations, (object)gridTypes, (object)gridObjectsDamagedIndexes, (object)gridObjectsDamagedHealth, (object)grayScaleIndexes, (object)grayScaleValues);
            }
            builtBlocks = new List<BuiltBlock>();
            healthUpdate = new Dictionary<int, float>();
            grayScaleUpdates = new Dictionary<int, float>();
        }
    }

    public void AddGrayScaleUpdate(int materialDrainValueIndex, float grayScale) {
        if (grayScaleUpdates.ContainsKey(materialDrainValueIndex)) {
            grayScaleUpdates[materialDrainValueIndex] += grayScale;
            return;
        }
        grayScaleUpdates.Add(materialDrainValueIndex, grayScale);
    }

    public void AddHealthUpdate(int gridIndex, float health) {
        if (healthUpdate.ContainsKey(gridIndex)) {
            healthUpdate[gridIndex] += health;
            return;
        }
        healthUpdate.Add(gridIndex, health);
    }

    [PunRPC]
    public void NetworkBuiltObjects(int[] indexes, float[] rotations, byte[] blockTypes, int[] damagedIndexes, float[] damagedHealth, int[] grayScaleIndexes, float[] grayScaleValues) {
        if (GridHandler.initializing) {
            StartCoroutine(WaitAndNetworkBuiltObjects(indexes, rotations, blockTypes, damagedIndexes, damagedHealth, grayScaleIndexes, grayScaleValues));
            return;
        }
        for (int i = 0; i < indexes.Length; i++) {
            buildHandler.BuildObjectRemotely(indexes[i], rotations[i], (BlockType)blockTypes[i]);
        }
        for(int i = 0; i < damagedIndexes.Length; i++) {
            buildHandler.DoDamageToBuiltObject(damagedIndexes[i], damagedHealth[i]);
        }
        for(int i = 0; i < grayScaleIndexes.Length; i++) {
            MaterialDrainValue materialDrainValueScript = MaterialDrainValue.GetMaterialDrainValue(grayScaleIndexes[i]);
            if (materialDrainValueScript) {
                materialDrainValueScript.HandleDrain(grayScaleValues[i]);
            }
            else {
                Debug.Log("no material drain value script found matching index: " + grayScaleIndexes[i]);
            }
        }
    }

    IEnumerator WaitAndNetworkBuiltObjects(int[] indexes, float[] rotations, byte[] blockTypes, int[] damagedIndexes, float[] damagedHealth, int[] grayScaleIndexes, float[] grayScaleValues) {
        while (GridHandler.initializing) {
            yield return null;
        }
        for (int i = 0; i < indexes.Length; i++) {
            buildHandler.BuildObjectRemotely(indexes[i], rotations[i], (BlockType)blockTypes[i]);
        }
        for (int i = 0; i < damagedIndexes.Length; i++) {
            buildHandler.DoDamageToBuiltObject(damagedIndexes[i], damagedHealth[i]);
        }
        for (int i = 0; i < grayScaleIndexes.Length; i++) {
            MaterialDrainValue materialDrainValueScript = MaterialDrainValue.GetMaterialDrainValue(grayScaleIndexes[i]);
            if (materialDrainValueScript) {
                materialDrainValueScript.HandleDrain(grayScaleValues[i]);
            }
            else {
                Debug.Log("no material drain value script found matching index: " + grayScaleIndexes[i]);
            }
        }
    }


    struct BuiltBlock {
        public int index;
        public float rotation;
        public BlockType blockType;

        public BuiltBlock(int _index, float _rotation, BlockType _blockType) {
            index = _index;
            rotation = _rotation;
            blockType = _blockType;
        }
    }

}
