using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using detect.device;
using detect.gui.Models.Entities;
using detect.gui.Services.Detect;
using Serilog;
using Splat;

namespace detect.gui.Services;

public class DeviceClientService
{
    private readonly IDictionary<long, IDeviceClient> _deviceClients = new Dictionary<long, IDeviceClient>();

    public DeviceClientService()
    {
        ConnectAllDevices();
        Log.Information("DeviceClientService Initialize Done.");
    }

    private static DeviceClientService? _instance;

    public static DeviceClientService Instance()
    {
        return _instance ??= new DeviceClientService();
    }

    /// <summary>
    /// 连接所有设备
    /// </summary>
    public void ConnectAllDevices()
    {
        var deviceService = Locator.Current.GetService<DetectDeviceService>()!;
        var devices = deviceService.ListAll().Result!;
        if (devices.Any())
        {
            devices.ForEach(device => { ConnectDevice(device); });
        }
    }

    /// <summary>
    /// 断开所有连接
    /// </summary>
    public void DisConnectAllDevices()
    {
        foreach (var (key, client) in _deviceClients)
        {
            client.DisConnectAsync();
        }
    }

    /// <summary>
    /// 根据设备id获取连接客户端
    /// </summary>
    /// <param name="deviceId"></param>
    /// <returns></returns>
    public IDeviceClient? GetDeviceClient(long deviceId)
    {
        _deviceClients.TryGetValue(deviceId, out var deviceClient);
        return deviceClient;
    }

    /// <summary>
    /// 刷新连接客户端，设备信息更新后调用
    /// </summary>
    /// <param name="deviceId"></param>
    /// <returns></returns>
    public IDeviceClient? RefreshDeviceClientById(long deviceId)
    {
        _deviceClients.TryGetValue(deviceId, out var deviceClient);
        deviceClient?.DisConnectAsync();
        var eventService = Locator.Current.GetService<DetectDeviceService>()!;
        return ConnectDevice(eventService.ListById(deviceId).Result!);
    }

    public void RefreshDeviceClientBySn(string deviceSn)
    {
        var device = Locator.Current.GetService<DetectDeviceService>()!.ListBySn(deviceSn).Result!;
        _deviceClients.TryGetValue(device.Id!.Value, out var deviceClient);
        deviceClient?.DisConnectAsync();
        DeleteDeviceClientById(device.Id!.Value);
        ConnectDevice(device);
        Log.Information("重新连接设备【" + device.Name + "】【" + device.DeviceIp + "】");
    }

    /// <summary>
    /// 刷新连接客户端，设备信息更新后调用
    /// </summary>
    /// <param name="device"></param>
    /// <returns></returns>
    public IDeviceClient? RefreshDeviceClient(DeviceEntity device)
    {
        _deviceClients.TryGetValue(device.Id!.Value, out var deviceClient);
        deviceClient?.DisConnectAsync();
        return ConnectDevice(device);
    }

    /// <summary>
    /// 断开连接并释放
    /// </summary>
    /// <param name="deviceId"></param>
    /// <returns></returns>
    public void DeleteDeviceClientById(long deviceId)
    {
        _deviceClients.TryGetValue(deviceId, out var deviceClient);
        deviceClient?.DisConnectAsync();
        _deviceClients.Remove(deviceId);
    }

    /// <summary>
    /// 连接云台设备
    /// </summary>
    /// <param name="device"></param>
    /// <returns></returns>
    public IDeviceClient? ConnectDevice(DeviceEntity device)
    {
        if (string.IsNullOrEmpty(device.DeviceIp))
        {
            Log.Warning("设备【{Name}】没有配置ip，不连接", device.Name);
            return null;
        }

        _deviceClients.TryGetValue(device.Id!.Value, out var deviceClient);
        if (deviceClient == null)
        {
            deviceClient = new DeviceClientSocket(device.DeviceIp!, 13000);
            deviceClient.ConnectAsync();
            _deviceClients.Add(device.Id!.Value, deviceClient);
        }
        else
        {
            if (!deviceClient.Connected())
            {
                deviceClient.ConnectAsync();
            }
        }

        deviceClient.DeviceEvent += DeviceClientOnDeviceEvent;

        return deviceClient;
    }

    private void DeviceClientOnDeviceEvent(object? sender, DeviceEvent e)
    {
        Log.Information("DeviceEvent-[{Name}]-{Address}:{@Result}", e.Name, (sender as DeviceClientSocket)!.Address,
            e.Result);
        if (e.Name == DeviceEvent.EventDeviceConnected)
        {
            // var sysInfo = GetDeviceInfo(1).GetAwaiter().GetResult();
            // Log.Information("device info: {@Info}", sysInfo);
            // test
            // AssignTasks(new long[] { 1 }).GetAwaiter();
        }

        // var deviceService = Locator.Current.GetService<VapDeviceService>()!;
        // var eventService = Locator.Current.GetService<VapEventService>()!;
        // var constantService = Locator.Current.GetService<VapConstantService>()!;
        // var deviceClient = sender as DeviceClientSocket;
        // var device = deviceService.ListByDeviceIp(deviceClient!.Address).Result!;
        // var eventEntity = new EventEntity
        // {
        //     RegionId = device.RegionId,
        //     DeviceId = device.Id,
        //     Code = e.Result["alarmType"] as string,
        //     AlarmLevel = "INFO",
        //     ImageUrl = $"http://{device.DeviceIp}:8000/{e.Result["image"] as string}",
        //     EventTime = DateTime.Parse((e.Result["datetime"] as string)!)
        // };
        // if (eventEntity.ImageUrl.StartsWith("http"))
        // {
        //     var constant = constantService.ListOne(code: VapConstantService.EVENT_DATA_SAVE_PATH).Result;
        //     var savePath = Path.Join(System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments),
        //         "aivap/event");
        //     if (constant != null)
        //     {
        //         savePath = constant.Value;
        //     }
        //     savePath = Path.Join(savePath, eventEntity.DeviceId.ToString());
        //     if (!Directory.Exists(savePath))
        //     {
        //         Directory.CreateDirectory(savePath!);
        //     }
        //     var filename = eventEntity.ImageUrl.Split("/").Last();
        //     var filePath = Path.Join(savePath!, filename);
        //     try
        //     {
        //         FileUtil.DownloadFileAsync(eventEntity.ImageUrl, filePath).GetAwaiter().GetResult();
        //         Log.Information("事件图片下载完成：{path}", filePath);
        //         eventEntity.ImageUrl = new FileInfo(filePath).FullName;
        //     }
        //     catch (Exception ex)
        //     {
        //         Log.Error(ex, "事件图片下载完成：{Error}", ex.Message);
        //     }
        // }
        // eventService.AddData(eventEntity);
    }

    #region 业务方法

    /// <summary>
    /// 查询设备信息
    /// </summary>
    /// <param name="deviceId"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public async Task<Dictionary<string, object>?> GetDeviceInfo(long deviceId)
    {
        var deviceClient = GetDeviceClient(deviceId);
        if (deviceClient == null)
        {
            throw new Exception("设备未连接！");
        }

        var req = DeviceClientRequestBuilder.Create().WithType("service").WithComponent("_database")
            .WithMethod("system_info");
        var resp = await deviceClient.RequestAction<Dictionary<string, object>>(req);
        if (resp.IsFailed)
        {
            throw new Exception(resp.Message);
        }

        return resp.Result;
    }

    public async Task<Dictionary<string, object>?> AssignTasks(long[] taskIds)
    {
        var taskService = Locator.Current.GetService<DetectTaskService>()!;
        var deviceService = Locator.Current.GetService<DetectDeviceService>()!;
        var taskList = taskService.ListByIds(taskIds).Result!;
        if (taskList.Count == 0)
        {
            throw new Exception("未选择需要下发的任务！");
        }

        var deviceSn = taskList[0].DeviceSn!;
        var device = deviceService.ListBySn(deviceSn).Result!;
        if (device == null)
        {
            throw new Exception("未找到设备！");
        }

        var deviceClient = GetDeviceClient(device.Id!.Value);
        if (deviceClient == null)
        {
            throw new Exception("设备未连接！");
        }

        if (!deviceClient.Connected())
        {
            throw new Exception("设备连接失败！");
        }

        var req = DeviceClientRequestBuilder.Create().WithType("service").WithComponent("dat_task")
            .WithMethod("add_server_tasks").WithParam("tasks", taskList);
        var resp = await deviceClient.RequestAction<Dictionary<string, object>>(req);
        if (resp.IsFailed)
        {
            throw new Exception(resp.Message);
        }

        return resp.Result;
    }

    public async Task SyncTasks(long[] taskIds)
    {
        var taskService = Locator.Current.GetService<DetectTaskService>()!;
        var deviceService = Locator.Current.GetService<DetectDeviceService>()!;
        var taskList = taskService.ListByIds(taskIds).Result!;
        if (taskList.Count == 0)
        {
            throw new Exception("未选择需要同步的任务！");
        }

        var deviceSn = taskList[0].DeviceSn!;
        var device = deviceService.ListBySn(deviceSn).Result!;
        if (device == null)
        {
            throw new Exception("未找到设备！");
        }

        var deviceClient = GetDeviceClient(device.Id!.Value);
        if (deviceClient == null)
        {
            throw new Exception("设备未连接！");
        }

        if (!deviceClient.Connected())
        {
            throw new Exception("设备连接失败！");
        }

        foreach (var task in taskList)
        {
            var req = DeviceClientRequestBuilder.Create().WithType("service").WithComponent("dat_task")
                .WithMethod("sync_client_tasks").WithParam("device_id", task.Id!.Value)
                .WithParam("device_sn", task.DeviceSn!);
            var resp = await deviceClient.RequestAction<Dictionary<string, object>>(req);
            if (resp.IsFailed)
            {
                throw new Exception(resp.Message);
            }

            if (resp.Result is null) continue;
            task.ResultJson = (string?)resp.Result!["result_json"];
            task.StartTime = Convert.ToDateTime(resp.Result!["start_time"]) == DateTime.MinValue
                ? null
                : Convert.ToDateTime(resp.Result!["start_time"]);
            task.EndTime = Convert.ToDateTime(resp.Result!["end_time"]) == DateTime.MinValue
                ? null
                : Convert.ToDateTime(resp.Result!["end_time"]);
            task.State = Convert.ToInt32((long)resp.Result!["state"]);
            task.Results = (string?)resp.Result!["results"];
            Locator.Current.GetService<DetectTaskService>()!.UpdateData(task);
        }
    }

    public Task<Dictionary<string, bool>?> GetDeviceConnected()
    {
        var r = new Dictionary<string, bool>();
        var deviceService = Locator.Current.GetService<DetectDeviceService>()!;
        var devices = deviceService.ListAll().Result!;
        if (devices.Count != 0)
        {
            devices.ForEach(device =>
            {
                _deviceClients.TryGetValue(device.Id!.Value, out var deviceClient);
                if (device.DeviceSn != null) r.Add(device.DeviceSn, deviceClient != null && deviceClient.Connected());
            });
        }

        return Task.FromResult(r.Count == 0 ? null : r);
    }

    // public Task RefreshDevice(long deviceId)
    // {
    //     RefreshDeviceClientById(deviceId);
    //     return Task.FromResult("");
    // }
    #endregion
}