using Assets.Scripts.Models;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class PlayerController : MonoBehaviour
{
    public static PlayerController instance;
    public Dictionary<uint, List<Structure>> Workers = new Dictionary<uint, List<Structure>>();
    public List<Structure> TestStructures = new List<Structure>();
    //public List<Beacon> Beacons = new List<Beacon>();

    public GameObject WorkersList; // scroll content

    public GameObject DateTimePanel;
    public GameObject StartHour;
    public GameObject StartMin;
    public GameObject StartSec;
    public GameObject EndHour;
    public GameObject EndMin;
    public GameObject EndSec;
    public GameObject StartStopButton;
    public LocationZones locationZones;
    //public GameObject ErrorDialog;
    public Dropdown DropdownMode;
    public Toggle ToggleLine;
    public Toggle ToggleDisappearance;

    public GameObject DatePicker;
    Camera camera;
    public Toggle projection;


    //public GameObject LocationGameObject;
    public GameObject UserInfo;

    public GameObject Editor;

    public uint? user_broadcast = null;
    public bool broadcast = false;
    public Dictionary<uint, User> users;
    public enum Mode { RealTime = 0, History = 1, Stop = 2 };
    public static Mode active_mode = Mode.Stop;
    int mode = 0;
    //public GameObject Time;

    Client client;
    CompanyController company;
    EditorController editor;

    DateTimePicker Date;

    public Dictionary<uint, bool> end_send = new Dictionary<uint, bool>(); // флаги завершения загрузки
    Dictionary<uint, MarkerMoving> moving = new Dictionary<uint, MarkerMoving>(); // флаги начала движения

    const float INTERPOLATION_PERIOD = 0.1f;
    //float time_realtime = 0;
    float time_draw = 0;
    //public List<User> users = new List<User>();
    public bool users_load = false;
    public bool beacons_load = false;


    //List<bool> StartStop = new List<bool>();

    private void Awake()
    {
        instance = this;
    }

    // Start is called before the first frame update
    void Start()
    {
        DebugHelper.ActivateConsole();
        client = Client.instance;
        company = CompanyController.instance;
        editor = Editor.GetComponent<EditorController>();
        camera = Camera.main;
        users = new Dictionary<uint, User>();

        Date = DatePicker.GetComponent<DateTimePicker>();
        //locations.Add(new Location { id = 1, name = "1 Братск" });
        //locations.Add(new Location { id = 22, name = "22 Офис Ижевск" });
        //locations.Add(new Location { id = 25, name = "25" });
        //locations.Add(new Location { id = 26, name = "26 Братское (вагрант)" });
        //foreach (var l in locations)
        //    DropdownLocation.options.Add(new Dropdown.OptionData(l.name));

        //for (int i = 0; i < Locations.transform.childCount; i++)
        //    maps.Add(Locations.transform.GetChild(i).gameObject);



        //Client.LocationsRequest();

        var broadcast_stop = UserInfo.transform.GetChild(1).GetChild(1).GetComponent<Button>();
        broadcast_stop.onClick.AddListener(() => BroadcastStop());
    }



    // Update is called once per frame
    void Update()
    {
        if (DropdownMode.value != mode)
            СhangeMode();


        time_draw += Time.deltaTime;
        if (time_draw >= INTERPOLATION_PERIOD)
        {
            MarkerMove();
            time_draw -= INTERPOLATION_PERIOD;
        }

        //if (active_mode == Mode.RealTime && !starting)
        //{
        //    foreach (var m in markers)
        //    {
        //        if (m.toggle.isOn)
        //        {
        //            Debug.LogWarning($"send {m.acc_id}");
        //            var index = company.locations_index[company.active_location];
        //            client.CoordinatesRequest(0, 0, 1, company.locations[index].id, m.acc_id);
        //            //end_send[m.acc_id] = false;
        //        }
        //    }
        //    starting = true;
        //}\\\\\

        if (ToggleLine.isOn)
        {
            foreach (var u in users)
                u.Value.marker_line.gameObject.SetActive(true);
            ToggleDisappearance.interactable = true;
        }
        else
        {
            foreach (var u in users)
            {
                u.Value.marker_line.gameObject.SetActive(false);
                u.Value.marker_line.positionCount = 0;
            }
            ToggleDisappearance.interactable = false;
        }

        if (projection.isOn)
        {
            camera.orthographic = true;
        }
        else
        {
            camera.orthographic = false;
        }

        if (users_load)
        {
            users_load = false;
            foreach (var u in users.OrderBy(u => u.Value.id))
            {
                //u.Value.WorkerMarker(u.Value, Color.green, WorkersList, BroadcastStart);
                //u.Value.toggle_user.transform.SetParent(WorkersList.transform);
                u.Value.SetParam(WorkersList, BroadcastStart);

                if (DropdownMode.value == 0) u.Value.toggle_user.SetActive(u.Value.online);
                else u.Value.toggle_user.SetActive(true);
            }
        }

        //LoadMaps(DropdownLocation, Locations);



        //if (locations.Any() && AuthorizationController.success)
        //{
        //    active_location = DropdownLocation.value;
        //    LoadLocation(locations[active_location]);
        //}
    }

  

    /// <summary>
    /// Смена положения маркера
    /// </summary>
    /// <param name="step">Шаг до нового положения</param>
    /// <param name="start_pos">Начальное положение</param>
    /// <param name="end_pos">Финальное положение</param>
    /// <param name="user">Маркер сотрудника</param>
    /// <param name="w">Данные из БД</param>
    /// <param name="progress">Номер записи из БД</param>
    /// <returns></returns>
    void Position(float step, Vector3 start_pos, Vector3 end_pos, User user, Structure w, string progress)
    {
        Debug.LogWarning($"move user {user.id} {end_pos} {w.ts} {w.zone_id}");
        if (user.marker.activeSelf == true)
        {
            var x_position = Mathf.Lerp(start_pos.x, end_pos.x, step);
            var y_position = Mathf.Lerp(start_pos.z, end_pos.z, step);
            //Debug.Log($"marker name={worker_marker.name} time={pause} step={step} sec x={x_position} y={y_position} x0={start_pos.x} y0={start_pos.z} x1={end_pos.x} y1={end_pos.z}");
            var new_position = new Vector3(x_position, 0.5f, y_position);
            if (user.marker.transform.position != new_position)
            {
                user.marker.transform.position = new Vector3(x_position, 0.5f, y_position);
                user.marker_line.SetPosition(user.marker_line.positionCount++, new Vector3(x_position, 0, y_position));
                if (ToggleDisappearance.isOn) user.marker_line = LineDisappearance(user.marker_line);
            }
            user.marker.transform.GetChild(0).transform.GetChild(0).transform.GetChild(0).GetComponent<Text>().text = $"{w.acc_id} x={end_pos.x} y={end_pos.z}";
            user.toggle.transform.GetChild(1).gameObject.GetComponent<Text>().text = $"{w.acc_id} {w.ts:HH:mm:ss}{progress}";
        }
    }



    /// <summary>
    /// Запуск отрисовки
    /// </summary>
    public void ButtonStart()
    {
        if (active_mode == Mode.Stop)
            foreach (var u in users)
                u.Value.marker_line.positionCount = 0;

        var button_text = StartStopButton.transform.GetChild(0);
        switch (DropdownMode.value)
        {
            case 0:
                //real_time = !real_time;
                if (active_mode == Mode.Stop/*real_time*/)
                {
                    active_mode = Mode.RealTime;
                    button_text.GetComponent<Text>().text = "Остановить";
                }
                else
                {
                    active_mode = Mode.Stop;
                    button_text.GetComponent<Text>().text = "Отобразить";
                }
                break;
            case 1:
                if (active_mode == Mode.Stop/*real_time*/) active_mode = Mode.History;
                else active_mode = Mode.Stop;

                if (active_mode == Mode.History/*history_start*/)
                {
                    var date = Date.Date;

                    var time_start = date; //new DateTime(dates.ElementAt(DropdownData.value).Ticks);
                    time_start = time_start.AddHours(int.Parse(StartHour.GetComponent<InputField>().text));
                    time_start = time_start.AddMinutes(int.Parse(StartMin.GetComponent<InputField>().text));
                    time_start = time_start.AddSeconds(int.Parse(StartSec.GetComponent<InputField>().text));
                    Debug.Log(time_start);
                    var time_end = date; //new DateTime(dates.ElementAt(DropdownData.value).Ticks);
                    time_end = time_end.AddHours(int.Parse(EndHour.GetComponent<InputField>().text));
                    time_end = time_end.AddMinutes(int.Parse(EndMin.GetComponent<InputField>().text));
                    time_end = time_end.AddSeconds(int.Parse(EndSec.GetComponent<InputField>().text));
                    foreach (var u in users)
                    {
                        if (u.Value.toggle.isOn)
                        {

                            client.CoordinatesRequest(time_start.Ticks, time_end.Ticks, 1, company.locations_index[company.active_location], u.Value.id);
                            end_send[u.Value.id] = false;
                        }
                    }
                    button_text.GetComponent<Text>().text = "Остановить";
                }
                else
                {
                    StopProgress();
                }
                break;
        }
    }



    public void StopProgress()
    {
        StartStopButton.transform.GetChild(0).GetComponent<Text>().text = "Отобразить";
        active_mode = Mode.Stop;
        foreach (var u in users)
        {
            end_send[u.Value.id] = false;
            moving.Remove(u.Value.id);
        }
    }

    /// <summary>
    /// Затухание траектории
    /// </summary>
    /// <param name="lineRenderer">Траектория</param>
    /// <returns></returns>
    LineRenderer LineDisappearance(LineRenderer lineRenderer)
    {
        //LineRenderer lineRenderer = GetComponent<LineRenderer>();
        int newPositionCount = lineRenderer.positionCount - 1;
        Vector3[] newPositions = new Vector3[newPositionCount];

        for (int i = 0; i < newPositionCount; i++)
        {
            newPositions[i] = lineRenderer.GetPosition(i + 1);
        }

        lineRenderer.SetPositions(newPositions);
        return lineRenderer;
    }

    /// <summary>
    /// Смена положения по интервалу
    /// Шаги для плавного перемещения
    /// </summary>
    /// <param name="u">Данные о маркере</param>
    void StartingAccPositiong(User u)
    {
        int i = 0;
        float step = 0.1f;
        if (moving.ContainsKey(u.id))
        {
            if (moving[u.id].index < Workers[u.id].Count) i = moving[u.id].index;
            if (moving[u.id].step < 1.1f) step = moving[u.id].step;
        }
        else moving[u.id] = new MarkerMoving();

        var worker = Workers[u.id];
        Debug.LogWarning($"worker coord count {u.id} {worker.Count}");      

        if (active_mode == Mode.RealTime) worker = worker.OrderBy(wr => wr.ts).ToList();
        if (worker.Any())
        {
            var w = worker[i];
           
            locationZones.UserPosition(u, w);           

            var start_pos = u.marker.transform.position;
            if (i != 0) start_pos = new Vector3(worker[i - 1].coord_x, 0.5f, worker[i - 1].coord_y);
            if (active_mode == Mode.History && i == 0) start_pos = new Vector3(w.coord_x, 0.5f, w.coord_y);

            var end_pos = new Vector3(w.coord_x, 0.5f, w.coord_y);

            var progress = "";
            if (active_mode == Mode.History) progress = $"\n{i + 1} из {Workers[u.id].Count}";
            //if (starting) 
            Position(step, start_pos, end_pos, u, w, progress);
            // StartingAccPositiong(m.value, time_step);

        }

        step += INTERPOLATION_PERIOD; // 0.1f;        
        moving[u.id].step = step;
        if (Math.Round(step, 1) > 1)
        {
            Debug.Log($"step:{step}");
            i++;
            moving[u.id].index = i;
        }

        if (active_mode == Mode.RealTime)
            if (Math.Round(step, 1) > 1)
            {
                Debug.Log($"Mode.RealTime step:{step}");
                Workers.Remove(u.id);
                Debug.LogWarning($"clear coord user {u.id}");
            }
        if (active_mode == Mode.History)
            if (i == Workers[u.id].Count)
            {
                //StopProgress();
                Workers.Remove(u.id);
            }
    }

    /// <summary>
    /// Отображение маяков
    /// </summary>
    /// <param name="b"></param>
    public static void AddBeacon(Beacon b)
    {
        var beacon = Instantiate(Resources.Load("GameObjects/Beacon", typeof(GameObject))) as GameObject;
        beacon.transform.position = new Vector3(b.x, 0.5f, b.y);
        beacon.name = $"BeaconButton_{b.id}";
        beacon.GetComponent<BeaconController>().info = false;
        beacon.transform.SetParent(GameObject.Find("Beacons").transform);
        beacon.transform.GetChild(0).GetChild(0).GetChild(0).GetComponent<Text>().text = $"{b.id}\nuuid={b.uuid}\nmajor={b.major}\nminor={b.minor}";

        b.beacon = beacon;
    }

    void OnGUI()
    {
        //if (Input.GetKeyDown(KeyCode.BackQuote)) 
        DebugHelper.DrawConsole();
    }

    /// <summary>
    /// Остановка отрисовки при смене режима история/онлайн
    /// </summary>
    public void СhangeMode()
    {
        StopProgress();

        active_mode = Mode.Stop;
        mode = DropdownMode.value;
        switch (DropdownMode.value)
        {
            case 0:
                DateTimePanel.SetActive(false);
                foreach(var u in users)
                    u.Value.toggle_user.SetActive(u.Value.online);
                break;
            case 1:
                DateTimePanel.SetActive(true);
                foreach (var u in users)
                    u.Value.toggle_user.SetActive(true);
                break;
        }
    }

    /// <summary>
    /// Смена позиции маркера
    /// </summary>
    public void MarkerMove()
    {
        foreach (var u in users)
        {
            if (u.Value.marker.activeSelf != u.Value.toggle.isOn) u.Value.marker.SetActive(u.Value.toggle.isOn);

            if (active_mode == Mode.RealTime && u.Value.toggle.isOn && !Workers.ContainsKey(u.Value.id))
            {
                Debug.LogWarning($"send coord user {u.Value.id}");                
                var index = company.locations_index[company.active_location];
                client.CoordinatesRequest(0, 0, 1, company.locations[index].id, u.Value.id);

                u.Value.toggle_user.SetActive(u.Value.online);
            }

            if (u.Value.toggle.isOn && Workers.ContainsKey(u.Value.id) && active_mode != Mode.Stop/*&& starting*/ /*&& end_send[m.value.acc_id]*/)
            {              
                StartingAccPositiong(u.Value);

                if (active_mode == Mode.History && !Workers.Any())
                {
                    //var temp = Workers.Values.Max(v => v.Count);
                    //if (m.i == temp - 1 && moving[moving.Keys.Last()].step >= 1f)
                    //{
                    StopProgress();
                    //}
                    //if (active_mode == Mode.RealTime && moving[moving.Keys.Last()].index == 1)
                    //{
                    //    starting = false;
                    //}
                }
            }
        }
    }

    /// <summary>
    /// Загрузка объектов локации
    /// </summary>
    /// <param name="location"></param>
    //public void LoadLocation(Location location)
    //{
    //    print("PlayerController.LoadLocation");
    //    if (load_location_elements.ContainsKey(location.id))
    //    {
    //        location.Load();
    //    }
    //}

    public void BroadcastStart(uint id)
    {
        if (user_broadcast.HasValue)
        {
            client.ImageStreamStopSend(user_broadcast.Value);
            var camera_button = users[user_broadcast.Value].toggle_user.transform.GetChild(1).GetComponent<Button>();
            camera_button.GetComponent<Image>().color = Color.white;
            broadcast = false;
        }
        if (user_broadcast != id)
        {
            client.ImageStreamStartSend(id);
            user_broadcast = id;
            var name = UserInfo.transform.GetChild(1).GetChild(0).GetComponent<Text>();
            name.text = $"{id} {users[id].name}";
            name.GetComponent<RectTransform>().sizeDelta = new Vector2(name.preferredWidth, 30);

            var camera_button = users[id].toggle_user.transform.GetChild(1).GetComponent<Button>();
            camera_button.GetComponent<Image>().color = Color.green;

            UserInfo.SetActive(false);
            broadcast = true;
        }
        else
        {
            broadcast = false;
            user_broadcast = null;
            UserInfo.SetActive(false);
        }
    }

    public void BroadcastStop()
    {
        if (user_broadcast.HasValue)
        {
            client.ImageStreamStopSend(user_broadcast.Value);
            var camera_button = users[user_broadcast.Value].toggle_user.transform.GetChild(1).GetComponent<Button>();
            camera_button.GetComponent<Image>().color = Color.white;
        }
        broadcast = false;
        user_broadcast = null;
        UserInfo.SetActive(false);
    }
}

