using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MegaRobo.Connections;
using MegaRobo.Connections.Web;
using MegaRobo.Contract;
using MegaRobo.ControlDevices.Abstractions;
using MegaRobo.Logger;

namespace MegaRobo.C00225155.ControlDevices;

/// <summary>
/// http://192.168.50.20:8888/swagger/index.html
/// </summary>
public sealed class AgvService : ConnectorBase, IConnection, IDisposable, IConnectionAsync
{
    public AgvService()
    {

    }

    public override async Task<string> Initialize(ICoreService coreService, params object[] args)
    {
        this.CoreService = coreService;
        try
        {
            if(args is [string hostname, ..])
            {
                this._hostname = hostname.Trim('/');
                this._httpService = new HttpClientEx { StringEncoder = Encoding.UTF8, BaseAddress = new Uri(this._hostname) };
                this._httpService.Timeout = TimeSpan.FromSeconds(5);

            }
        } catch(Exception ex)
        {
            this.Logger.LogException(ex);
        }
        await Task.Delay(0);
        return string.Empty;
    }

    private string _hostname = "";
    
    private HttpClientEx _httpService;
    public decimal ChargeVolume { get; set; } // 电量 0-1 即为 100%为满电
    public string CurrentStationName { get; set; } = string.Empty;
    public bool IsInChargeLocation => false;
    public bool IsInWaitLocation => false;

    public string ChargeLocationCode { get; set; }
    public string WaitLocationCode { get; set; }

    public string TargetLocation = "";

    public override async Task<ConnectionState> CheckConnected()
    {
        await Task.Delay(0);
        return ConnectionState.IsConnected;
    }

    public override async Task<ConnectionState> ReconnectAsync()
    {
        await Task.Delay(0);
        return ConnectionState.IsConnected;
    }

    #region Status

    public async Task<bool> CheckMoveDone()
    {
       var currStation= await this.ReadCurrentStation();
       if(string.IsNullOrWhiteSpace(currStation) || string.IsNullOrWhiteSpace(this.TargetLocation))
       {
           return false;
       }
       return string.Equals(currStation, this.TargetLocation, StringComparison.CurrentCultureIgnoreCase);
    }
    public async Task<bool> CheckMoveing()
    {
        try
        {
            this.CurrentStationName = await this.ReadCurrentStation();
        } catch(Exception ex)
        {
            this.Logger.LogException(ex);
        }
        return false;
    }

    #endregion Status

    #region Init

    public async void Comfirmloc()
    {
        try
        {
            string apiName = "/RobotControl/Comfirmloc";
            var response = await this._httpService.PostJsonAsync(apiName, string.Empty);
            this.Logger.LogDebug(response);
        } catch(Exception ex)
        {
            this.Logger.LogException(ex);
        }
    }

    public async void Lock(string name = "mega")
    {
        try
        {
            string apiName = this._hostname + "/RobotConfig/Lock";
            // var args = new { nick_name = name };
            //var response = await this._httpService.PostJsonAsync(apiName, args.ToJson());
            IDictionary<string, string> argdict = new Dictionary<string, string>();
            argdict.Add("nick_name", name);
            apiName = this._httpService.UrlCombine(apiName, argdict);
            var response = await this._httpService.PostJsonAsync(apiName, string.Empty);
            this.Logger.LogInformation(response);
        } catch(Exception ex)
        {
            this.Logger.LogException(ex);
        }
    }

    public async void Unlock()
    {
        try
        {
            string apiName = "/RobotConfig/Unlock";
            var response = await this._httpService.PutAsync(apiName, null);

            if(response.IsSuccessStatusCode)
            {
                this.Logger.LogInformation($"释放控制权");
            }
        } catch(Exception ex)
        {
            this.Logger.LogException(ex);
        }
    }

    #endregion Init

    #region 状态

    /// <summary>
    /// AGV电量
    /// </summary>
    /// <returns></returns>
    public async Task<string> ReadBattery()
    {
        try
        {
            string apiName = this._hostname + "/RobotStatus/Battery";
            IDictionary<string, string> argdict = new Dictionary<string, string>();
            argdict.Add("simple", false.ToString());
            apiName = this._httpService.UrlCombine(apiName, argdict);
            var response = await this._httpService.GetStringAsync(apiName);
            var batteryLevel = response.GetJsonValueByToken<string>("data.battery_level");
            return batteryLevel;
        } catch(Exception ex)
        {
            this.Logger.LogException(ex);
        }
        return null;
    }

    public async Task<string> ReadCurrentStation()
    {
        try
        {
            string apiName = this._hostname + "/RobotStatus/Loc";
            IDictionary<string, string> argDict = new Dictionary<string, string>();
            argDict.Add("simple", false.ToString());
            apiName = this._httpService.UrlCombine(apiName, argDict);
            var response = await this._httpService.GetStringAsync(apiName);
            var currentStation = response.GetJsonValueByToken<string>("data.current_station");
            return currentStation;
        } catch(Exception ex)
        {
            this.Logger.LogException(ex);
        }
        return null;
    }

    public async Task<bool> ReadTaskStatus()
    {
        try
        {
            //https://support.seer-group.com/d/1674676593139699713.html
            string apiName = this._hostname + "/RobotStatus/Task";
            // IDictionary<string, string> argdict = new Dictionary<string, string>();
            // argdict.Add("simple", false.ToString());
            apiName = this._httpService.UrlCombine(apiName, null);
            var response = await this._httpService.GetStringAsync(apiName);
            var taskStatus = response.GetJsonValueByToken<string>("data.task_status");
            return new[] { "2", "3" }.Contains(taskStatus);
        } catch(Exception ex)
        {
            this.Logger.LogException(ex);
        }
        return false;
    }

    public async Task ClearAllErrors()
    {
        try
        {
            string apiName = this._hostname + "/RobotConfig/Clearallerrors";
            // IDictionary<string, string> argdict = new Dictionary<string, string>();
            // argdict.Add("simple", false.ToString());
            apiName = this._httpService.UrlCombine(apiName, null);
            var response = await this._httpService.GetStringAsync(apiName);
            response.GetJsonValueByToken<string>("data.ret_code");
        } catch(Exception ex)
        {
            this.Logger.LogException(ex);
        }
    }
    #endregion

    #region Move

    private async Task<string> LoadCurrentLocationAsync()
    {
        try
        {
            string apiName = this._hostname + "/RobotStatus/Loc";
            var response = await this._httpService.GetStringAsync(apiName);
            var currentStation = response.GetJsonValueByToken<string>("data.current_station");
            return currentStation;
        } catch(Exception ex)
        {
            Console.WriteLine(ex);
        }
        return null;
    }

    public async void MoveToLocation(string location)
    {
        try
        {
            this.TargetLocation = location;
            this.Comfirmloc();
            string apiName = this._hostname + "/RobotTask/Gotarget";
            string sourceId = "SELF_POSITION";

            // sourceId = await this.LoadCurrentLocationAsync();
            var locationItem = new { id = location, source_id = sourceId, task_id = $"goto_{DateTime.Now:yyyyMMdd_HHmmssfff}_{location}" };
            var jsonRaw = locationItem.ToJson(true);
            var response = await this._httpService.PostJsonAsync(apiName, jsonRaw);
            this.Logger.LogInformation(response);
        } catch(Exception ex)
        {
            Console.WriteLine(ex);
        }
    }

    /// <summary>
    /// 指定路过某点到某点
    /// 优点: 会按照任务发送队列执行
    /// 缺点: 假如同命令连续发送多次，可能会造成首次命令执行后原地掉头导致碰撞风险;
    /// </summary>
    /// <param name="locations"></param>
    public async void MoveToLocation(IList<string> locations)
    {
        if(locations == null || !locations.Any())
            return;
        try
        {
            this.Comfirmloc();
            string apiName = this._hostname + "/RobotTask/Gotargetlist";
            string sourceId = "SELF_POSITION";

            sourceId = await this.LoadCurrentLocationAsync();
            IList<object> orderList = new List<object>();
            for(var index = 0; index < locations.Count; index++)
            {
                string item = locations[index];
                if(index > 0)
                {
                    sourceId = locations[index - 1];
                }
                var locationItem = new { id = item, source_id = sourceId, task_id = $"goto_{DateTime.Now:yyyyMMdd_HHmmssfff}_{item}" };
                orderList.Add(locationItem);
            }
            var args = new { move_task_list = orderList };
            var jsonRaw = args.ToJson(true);
            var response = await this._httpService.PostJsonAsync(apiName, jsonRaw);
            this.Logger.LogInformation(response);
        } catch(Exception ex)
        {
            Console.WriteLine(ex);
        }

    }

    #endregion Move

    #region Watcher

    #endregion Watcher
}