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

public class WallCreate : MonoBehaviour
{
    public static WallCreate instance;

    public static float WallHeight = 1f;
    public float WallThickness = 0.05f;
    public int Rounding = 1;
    public bool move = false;
    public bool BoxColliderEnabled = true;
    public Dialog Dialog;
    public GameObject ZonesScroll;
    public GameObject Player;

    public Button redo;
    public Button undo; // отмена
    public List<History> histories = new List<History>();

    public enum Mode { Wall, Room, Zone, Pole, Cursor };
    public static Mode mode = Mode.Cursor;
    GameObject wall;
    Wall currentWall;
    //public Dictionary<uint, GameObject> WallObjects = new Dictionary<uint, GameObject>();
    public static Dictionary<uint, List<Wall>> Walls = new Dictionary<uint, List<Wall>>();
    //public static List<Wall> Rooms = new List<Wall>();
    public static Dictionary<uint, List<Zone>> Zones = new Dictionary<uint, List<Zone>>();

    private Vector3 screenPoint;
    private Vector3 offset;
    private Vector3 curScreenPoint;
    private Vector3 curPosition;

    private Vector3 start_pos;
    Vector3 Point;

    GameObject canvas;
    Text text;

    CompanyController company;

    private void Awake()
    {
        instance = this;
    }

    // Start is called before the first frame update
    void Start()
    {
       // gameObject.GetComponent<BoxCollider>().enabled = BoxColliderEnabled;
        //cursor_end = transform.GetChild(6).gameObject; 
        Point = Camera.main.WorldToScreenPoint(gameObject.transform.position);
        canvas = transform.GetChild(0).gameObject;
        text = transform.GetChild(0).GetChild(0).GetChild(0).GetComponent<Text>();
        company = CompanyController.instance;

        undo.onClick.AddListener(Undo);
    }
   
    // Update is called once per frame
    void Update()
    {
        // if (gameObject.GetComponent<BoxCollider>().enabled != BoxColliderEnabled) gameObject.GetComponent<BoxCollider>().enabled = BoxColliderEnabled;
        if (!Input.GetMouseButtonDown(0))
        {           
            transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Point.z));
            if (transform.position.y != 0.5f) transform.position = new Vector3(transform.position.x, 0.5f, transform.position.z);
        }
    }

    void OnMouseDown()
    {
        if (!EventSystem.current.IsPointerOverGameObject())
        {
            //Debug.Log(StagesEditorController.indexCursor);

            screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position);
            //s_point = Camera.main.WorldToScreenPoint(gameObject.transform.position);
            start_pos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
            offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));

            switch (mode)
            {
                case Mode.Wall:
                    wall = AddWall(company, Vector3.zero);
                    EventHistory(0, wall, null);
                    break;
                case Mode.Room:
                    wall = AddRoom();
                    break;
                case Mode.Zone:
                    wall = AddZone(Dialog, company, ZonesScroll);

                    var location_id = company.locations_index[company.active_location];
                    EventHistory(0, wall, Zones[location_id].Last().buttons);
                    break;
            }

           
        }

        canvas.SetActive(true);       
    }

    float scale_x;
    float scale_z;
    void OnMouseDrag()
    {
        if (!EventSystem.current.IsPointerOverGameObject())
        {
            curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
            // e_point = Camera.main.WorldToScreenPoint(gameObject.transform.position);
            curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;

            var end_pos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
            //Debug.Log("start_pos.x "+start_pos.x);
            scale_x = (float)Math.Round(end_pos.x - start_pos.x, Rounding);
            scale_z = (float)Math.Round(end_pos.z - start_pos.z, Rounding);
            text.text = $"x={scale_x} y={scale_z}";           
           
            switch (mode)
            {
                case Mode.Wall:
                    if (Math.Abs(scale_x) > Math.Abs(scale_z)/* && x_mod >= 0.4f*/)
                    {
                        wall.transform.localScale = new Vector3(scale_x, WallHeight, WallThickness);
                        wall.transform.position = new Vector3(scale_x / 2 + start_pos.x, WallHeight / 2, start_pos.z);
                    }
                    if (Math.Abs(scale_z) > Math.Abs(scale_x)/* && z_mod >= 0.4f*/)
                    {

                        wall.transform.localScale = new Vector3(WallThickness, WallHeight, scale_z);
                        wall.transform.position = new Vector3(start_pos.x, WallHeight / 2, scale_z / 2 + start_pos.z);
                    }

                    break;
                case Mode.Room:
                    /*if (scale_x > 0 && scale_z > 0) */
                    LocationController.Cube(wall, new Vector3(scale_x, scale_z, WallHeight),
                                                            new Vector2((float)Math.Round(start_pos.x, Rounding), (float)Math.Round(start_pos.z, Rounding)), WallThickness);
                    break;
                //case Mode.Pole:
                //    AddWall(pos);
                //    break;
                case Mode.Zone:
                    wall.transform.localScale = new Vector3(scale_x/10, 1, scale_z/10);
                    wall.transform.position = new Vector3(scale_x / 2 + start_pos.x, 0.05f, scale_z / 2 + start_pos.z);
                    break;
            }

            float offsetPosY = transform.position.y + 1.5f;

            // Final position of marker above GO in world space
            canvas.transform.GetChild(0).transform.position = new Vector3(Input.mousePosition.x, Input.mousePosition.y+20, screenPoint.z);
        }
    }

    private void OnMouseUp()
    {
        //var end_pos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
        //Debug.Log($"end_pos = {end_pos}");

        var location_id = company.locations_index[company.active_location];
        if (!Walls.ContainsKey(location_id)) 
            Walls[location_id] = new List<Wall>();
        if (mode == Mode.Room)
        {
            for (int i = 0; i < wall.transform.childCount; i++)
            {
                var w = wall.transform.GetChild(i);
                if(w.gameObject.activeSelf == true)
                {
                    currentWall = new Wall { id = Convert.ToUInt32(4000000000 + Walls[location_id].Count),location_id = location_id, start_width = w.position.x, start_height = w.position.z, end_width = w.localScale.x, end_height = w.localScale.z, go = wall };
                    Walls[location_id].Add(currentWall);
                }
            }
        }

        //if (mode == Mode.Room) Rooms.Add(currentWall);
        if (mode == Mode.Wall)
        {
            currentWall = new Wall { id =Convert.ToUInt32(4000000000 + Walls[location_id].Count), start_width = wall.transform.position.x, start_height = wall.transform.position.z, end_width = wall.transform.localScale.x, end_height = wall.transform.localScale.z, go = wall, location_id=location_id };
            Debug.Log($"new wall save id {currentWall.id}  x {currentWall.start_width} z {currentWall.start_height} x2 {currentWall.end_width} z2 {currentWall.end_height} location_id {currentWall.location_id}");
            Walls[location_id].Add(currentWall);
        }
        
        /*if (mode == Mode.Wall || mode == Mode.Room)*/ /*Walls.Add(currentWall);*/

        canvas.SetActive(false);

        if (mode == Mode.Zone && !EventSystem.current.IsPointerOverGameObject())
        {
            Dialog.GetComponent<Dialog>().Text.gameObject.SetActive(false);
            Dialog.GetComponent<Dialog>().InputField.gameObject.SetActive(true);
            Dialog.GetComponent<Dialog>().Button.onClick.AddListener(() =>
            {
                wall.GetComponent<ZoneController>().TextMesh.text=Dialog.GetComponent<Dialog>().InputField.text;
            });

            var z = Zones[location_id][last_zone];            
            z.start_width = wall.transform.position.x;
            z.start_height = wall.transform.position.z;          
            z.end_width = wall.transform.localScale.x;
            z.end_height = wall.transform.localScale.z;
            Debug.Log($"z {z.id} z.start_width {z.start_width} z.start_height {z.start_height}");
            //Zones[location_id].Insert(last_zone, z);
        }                
    }

    public static GameObject AddWall(CompanyController company, Vector3 pos, Vector3 scale = default)
    {
        var wall = Instantiate(Resources.Load("GameObjects/Wall", typeof(GameObject))) as GameObject;
        wall.transform.position = pos;
        if (scale != null) wall.transform.localScale = scale;
        var location = company.locations[company.locations_index[company.active_location]].location;
        wall.transform.SetParent(location.transform.GetChild(1).transform);
        //WallObjects.Add(wall);
        
        return wall;
    }

    GameObject AddRoom()
    {
        var room = Instantiate(Resources.Load("GameObjects/Cube", typeof(GameObject))) as GameObject;
        var location = company.locations[company.locations_index[company.active_location]].location;
        room.transform.SetParent(location.transform.GetChild(1).transform);
        LocationController.Cube(room, new Vector3(0.1f, 0.1f, 1));
        //for (var i = 0; i < room.transform.childCount; i++)
        //    if (room.transform.GetChild(i).gameObject.activeSelf == true)            
        //        WallObjects.Add(room.transform.GetChild(i).gameObject);
            
        return room;
    }

    static int last_zone;
    public static GameObject AddZone(Dialog Dialog, CompanyController company, GameObject ZonesScroll, Zone z = null)
    {        
        var location = company.locations[company.locations_index[company.active_location]].location;
        var location_id = company.locations_index[company.active_location];        

        if (!Zones.ContainsKey(location_id)) Zones[location_id] = new List<Zone>();        
        
        var zone = Instantiate(Resources.Load("GameObjects/Zone", typeof(GameObject))) as GameObject;
        zone.name = $"Zone_{Zones[location_id].Count + 1}";
        var zname = $"Зона {Zones[location_id].Count + 1}";
        if (z != null) zname = z.name;                       
        
        //zone.transform.position = pos;

        zone.transform.SetParent(location.transform.GetChild(2).transform);

        var panel_button = Instantiate(Resources.Load("GameObjects/Panel_Beacon", typeof(GameObject))) as GameObject;
        panel_button.transform.SetParent(ZonesScroll.transform);
       
        var button = panel_button.transform.GetChild(0).GetComponent<Button>();
        button.transform.GetChild(0).GetComponent<Text>().text = zname;
        var tm = zone.GetComponent<ZoneController>().TextMesh;
       tm.text = zname;
        //tm.transform.parent = null;
        //tm.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
        //tm.transform.parent=zone.transform;

        var active_zone = Zones[location_id].Count;
         panel_button.name = $"Zone_{active_zone}";
        if(z == null) z = new Zone { id= Convert.ToUInt32(4000000000 + Zones[location_id].Count), location_id= location_id };   
        else
        {
            zone.transform.position = new Vector3(Mathf.Abs(z.start_width), 0.05f, Mathf.Abs(z.start_height));
            zone.transform.localScale = new Vector3(Mathf.Abs(z.end_width), 1, Mathf.Abs(z.end_height));
            zone.name = $"Zone_{z.id}";
            company.LocationZones.AddZone(z);
        }
        z.buttons = panel_button;
        z.go = zone;

        var button_ok = Dialog.transform.GetChild(2).GetComponent<Button>();
        
        button.onClick.AddListener(() =>
        {
            Dialog.gameObject.SetActive(true);
            //active_zone = Zones[location_id].Count;
            button_ok.onClick.RemoveAllListeners();

            Dialog.Text.gameObject.SetActive(false);
            Dialog.InputField.gameObject.SetActive(true);
            Dialog.InputField.text = !z.name.Equals("") ? z.name : $"Зона {active_zone + 1}";

            button_ok.onClick.AddListener(() =>
            {                                
                var name = !Dialog.GetComponent<Dialog>().InputField.text.Equals("") ? Dialog.GetComponent<Dialog>().InputField.text : $"Зона {active_zone + 1}";
                button.transform.GetChild(0).GetComponent<Text>().text = name;
                zone.GetComponent<ZoneController>().TextMesh.text = name;
                Dialog.gameObject.SetActive(false);
                z.name = name;
                //Zones[location_id].Insert(last_zone, z);
            });           
        });

        var button_del = panel_button.transform.GetChild(2).GetComponent<Button>();
        button_del.onClick.AddListener(() =>
        {
            Destroy(zone);
            Destroy(panel_button);
            Zones[location_id].Remove(z);
        });

        Zones[location_id].Add(z);
        last_zone = Zones[location_id].Count - 1;
        return zone;
    }

    //public void SaveZones()
    //{
    //    foreach(var z in Zones)
    //    {
    //        z.Save();
    //    }
    //}

    static uint WallGetInnerID(uint location_id, int num)
    {
        var wall = Walls[location_id][num];
        return wall.id;
    } 
    
    static uint ZoneGetInnerID(uint location_id, int num)
    {
        var zone = Zones[location_id][num];
        return zone.id;
    }

    void Undo()
    {
        var last = histories.Last();
        last.obj.SetActive(false);
        if(last.ButtonPanel != null) last.ButtonPanel.SetActive(false);
        last.status = false;
    }

    public void EventHistory(uint id, GameObject gameObject, GameObject panel)
    {
        histories.Add(new History { id = id, obj = gameObject, ButtonPanel = panel, status = true });
    }
}
