using System.Collections.Concurrent;
using System.Data;
using System.IO;
using System.Threading;
using DotNetCore.CAP;
using Fw.Utility.Client;
using Google.Protobuf.WellKnownTypes;
using Hotline.Ai.Visit;
using Hotline.Application.ExportExcel;
using Hotline.CallCenter.BlackLists;
using Hotline.CallCenter.Calls;
using Hotline.CallCenter.Devices;
using Hotline.CallCenter.Ivrs;
using Hotline.FlowEngine.WorkflowModules;
using Hotline.FlowEngine.Workflows;
using Hotline.Identity.Roles;
using Hotline.Import;
using Hotline.Orders;
using Hotline.Realtimes;
using Hotline.Repository.SqlSugar;
using Hotline.Repository.SqlSugar.System;
using Hotline.Repository.SqlSugar.Ts;
using Hotline.Settings;
using Hotline.Settings.TimeLimits;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.FlowEngine;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Dtos.Realtime;
using Hotline.Share.Enums.FlowEngine;
using Hotline.Share.Enums.Settings;
using Hotline.Share.Mq;
using Hotline.Tools;
using Hotline.Users;
using MapsterMapper;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing.Template;
using Microsoft.Extensions.Options;
using MiniExcelLibs;
using NewRock.Sdk;
using NewRock.Sdk.Security;
using SqlSugar;
using SqlSugar.SplitTableExtensions;
using Tr.Sdk;
using XC.RSAUtil;
using XF.Domain.Authentications;
using XF.Domain.Cache;
using XF.Domain.Entities;
using XF.Domain.Exceptions;
using XF.Domain.Filters;
using XF.Domain.Locks;
using XF.Domain.Queues;
using XF.Domain.Repository;
using XF.EasyCaching;

namespace Hotline.Api.Controllers;

/// <summary>
/// 
/// </summary>
[AllowAnonymous]
public class TestController : BaseController
{
    private readonly ILogger<TestController> _logger;
    private readonly IAuthorizeGenerator _authorizeGenerator;
    private readonly IOptionsSnapshot<CallCenterConfiguration> _options;
    private readonly ISessionContext _sessionContext;
    private readonly IRepository<User> _userRepository;

    private readonly ITypedCache<User> _cache;
    private readonly IRealtimeService _realtimeService;
    private readonly IBlacklistDomainService _blacklistDomainService;
    private readonly IIvrDomainService _ivrDomainService;
    private readonly ISugarUnitOfWork<HotlineDbContext> _uow;
    private readonly IRepository<Role> _roleRepository;
    private readonly IMediator _mediator;

    private readonly IDistributedLock _distributedLock;
    private readonly IRepository<OrderUrge> _orderUrgeRepository;
    private readonly IRepositoryTextSearch<OrderTs> _repositoryts;

    private readonly ITimeLimitDomainService _timeLimitDomainService;
    private readonly IWfModuleDomainService _wfModuleDomainService;
    private readonly IDaySettingRepository _daySettingRepository;
    private readonly ITrClient _trClient;
    private readonly ICapPublisher _capPublisher;
    private readonly IQueue _queue;
    private readonly IExportApplication _exportApplication;
    private readonly IAiVisitService _aiVisitService;
    private readonly IRepository<WorkflowTrace> _workflowTraceRepository;

    private readonly IRepository<WorkflowStep> _workflowStepRepository;
    //private readonly IRepository<WorkflowStepHandler> _workflowStepHandleRepository;

    private readonly IRepository<SystemOrganize> _systemOrganizeRepository;
    private readonly IOrderRepository _orderRepository;
    private readonly IMapper _mapper;


    //private readonly ITypedCache<List<User>> _cache;
    //private readonly ICacheManager<User> _cache;


    public TestController(
        INewRockClient client,
        ILogger<TestController> logger,
        IAuthorizeGenerator authorizeGenerator,
        IOptionsSnapshot<CallCenterConfiguration> options,
        ISessionContext sessionContext,
        IRepository<User> userRepository,
        //ICacheManager<User> cache
        //ITypedCache<List<User>> cache
        ITypedCache<User> cache,
        IRealtimeService realtimeService,
        IBlacklistDomainService blacklistDomainService,
        IIvrDomainService ivrDomainService,
        ISugarUnitOfWork<HotlineDbContext> uow,
        IRepository<Role> roleRepository,
        IMediator mediator,
        IDistributedLock distributedLock,
        IRepository<OrderUrge> orderUrgeRepository,
        IRepositoryTextSearch<OrderTs> repositoryts,
        ITimeLimitDomainService timeLimitDomainService,
        IWfModuleDomainService wfModuleDomainService,
        IDaySettingRepository daySettingRepository,
        ITrClient trClient,
        ICapPublisher capPublisher,
        IQueue queue,
        IExportApplication exportApplication,
        IAiVisitService aiVisitService,
        IRepository<WorkflowTrace> workflowTraceRepository,
        IRepository<WorkflowStep> workflowStepRepository,
        //IRepository<WorkflowStepHandler> workflowStepHandleRepository,
        IRepository<SystemOrganize> systemOrganizeRepository,
        IOrderRepository orderRepository,
        IMapper mapper
        )
    {
        _logger = logger;
        _authorizeGenerator = authorizeGenerator;
        _options = options;
        _sessionContext = sessionContext;
        _userRepository = userRepository;
        _cache = cache;
        _realtimeService = realtimeService;
        _blacklistDomainService = blacklistDomainService;
        _ivrDomainService = ivrDomainService;
        _uow = uow;
        _roleRepository = roleRepository;
        _mediator = mediator;
        _distributedLock = distributedLock;
        _orderUrgeRepository = orderUrgeRepository;
        _repositoryts = repositoryts;
        _timeLimitDomainService = timeLimitDomainService;
        _wfModuleDomainService = wfModuleDomainService;
        _daySettingRepository = daySettingRepository;
        _trClient = trClient;
        _capPublisher = capPublisher;
        _queue = queue;
        _exportApplication = exportApplication;
        _aiVisitService = aiVisitService;
        _workflowTraceRepository = workflowTraceRepository;
        _workflowStepRepository = workflowStepRepository;
        //_workflowStepHandleRepository = workflowStepHandleRepository;
        _systemOrganizeRepository = systemOrganizeRepository;
        _orderRepository = orderRepository;
        _orderRepository = orderRepository;
        _mapper = mapper;
    }

    [HttpGet("testo")]
    public async Task<OpenResponse> TestOrigin()
    {
        var now = DateTime.Now.ToString();
        return OpenResponse.Ok(now);
    }


    [HttpGet("init-orgname")]
    [AllowAnonymous]
    public async Task InitUserOrgFullName()
    {
        var list = await _userRepository.Queryable().Where(x => 1 == 1 && string.IsNullOrEmpty(x.FullOrgName)).ToListAsync();

        foreach (var item in list)
        {
            var orgFullName = "";
            var orgFullCode = "";
            var orgId = item.OrgId;
            int strLength = orgId.Length;
            int segmentsCount = strLength / 3;
            List<string> strings = new List<string>();

            for (int i = 0; i < segmentsCount; i++)
            {
                int startIndex = i * 3;
                int length = Math.Min(3, strLength - startIndex);
                strings.Add(orgId.Substring(startIndex, length));
            }

            if (strLength > 3)
            {
                orgFullCode = strings[0];
                strings.Remove(orgFullCode);

            }

            foreach (var str in strings)
            {
                orgFullCode = orgFullCode + str;

                var org = await _systemOrganizeRepository.GetAsync(orgFullCode);
                if (org != null)
                {

                    orgFullName = orgFullName + org.Name + "/";
                }
            }
            if (orgFullName.Length > 0)
            {
                orgFullName = orgFullName.Remove(orgFullName.Length - 1);
            }
            item.FullOrgName = orgFullName;
            await _userRepository.UpdateAsync(item);
        }
    }



    [HttpPost("import")]
    [AllowAnonymous]
    public async Task<List<ExcelContent>> Import(IFormFile file)
    {
        //var FileName = file.FileName;
        //var fileExtension = Path.GetExtension(FileName);
        ////新文件名
        //var newFileName = DateTime.Now.ToString("yyyyMMddhhmmss");
        ////文件保存路径
        //var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "Upload", newFileName);
        ////判断路径是否存在
        //if (!Directory.Exists(filePath))
        //{
        //    //创建路径
        //    Directory.CreateDirectory(filePath);
        //}
        //filePath = Path.Combine(filePath, newFileName+ fileExtension);
        using (var stream = new MemoryStream())
        {
            file.CopyTo(stream);
            var list = MiniExcel.Query<ExcelContent>(stream).ToList();
            //Directory.Delete(filePath, true);
            return list;
        }

    }

    [AllowAnonymous]
    [HttpGet("export")]
    public async Task<object> Export()
    {
        List<ExcelContent> list = new List<ExcelContent>();
        ExcelContent excelContent = new ExcelContent() { ExternalId = "123123" };
        list.Add(excelContent);
        return _exportApplication.ExportData<ExcelContent>(list, "demo.xlsx");
    }



    [HttpGet("time")]
    [AllowAnonymous]
    public async Task<OpenResponse> GetTime(string batchId, string taskId)
    {
        //await _repositoryts.AddVectorAsync("f595e730-909a-45e4-9138-a84bf15f4662", DateTime.Now,
        //    new List<string> { "xx", "bb" }, HttpContext.RequestAborted);

        //await _repositoryts.AddVectorAsync("f595e730-909a-45e4-9138-a84bf15f4663", DateTime.Now,
        //    new List<string> { "aa", "bb", "cc" }, HttpContext.RequestAborted);

        var result0 = await _repositoryts.SearchAsync(new List<string> { "xx", "aa" }, HttpContext.RequestAborted);
        var result = await _repositoryts.SearchAsync(new List<string> { "bb" }, HttpContext.RequestAborted);
        var result1 = await _repositoryts.SearchAsync(new List<string> { "cc", "bb" }, HttpContext.RequestAborted);
        var result2 = await _repositoryts.SearchAsync(new List<string> { "cc", "xx" }, HttpContext.RequestAborted);
        var result3 = await _repositoryts.SearchAsync(new List<string> { "aa", "bb", "ss" }, HttpContext.RequestAborted);

        //await _repositoryts.UpdateVectorAsync("f595e730-909a-45e4-9138-a84bf15f4662",
        //    new List<string> { "ss", "bb" }, HttpContext.RequestAborted);

        //_uow.Db.Ado.SqlQueryAsync<OrderUrge>("SELECT to_tsvector('fat cats ate fat rats') @@ to_tsquery('fat & rat')")

        //var tests = _uowWex.Db.Ado.SqlQuery<Test>("select * from view_telinfo_full where IsSynch=@IsSynch", new { IsSynch = 0 });
        //var a = _uowWex.Db.Ado.ExecuteCommand("update telinfo set IsSynch=1 where GUID=@CallId", new { CallId = "b1f97f3c-88b6-4f42-b8de-83ed448854b0" });
        //var rsp = await _wexClient.QueryTelsAsync(new QueryTelRequest {  }, HttpContext.RequestAborted);

        //int a = _timeLimitDomainService.CalcWorkTime(DateTime.Now, DateTime.Parse("2023-09-11 16:21:00"));
        //int m = _timeLimitDomainService.CalcWorkTime(DateTime.Parse("2023-09-19 12:00:00"), DateTime.Parse("2023-09-20 18:00:00"), false);
        //var r = _timeLimitDomainService.CalcEndTime(DateTime.Parse("2024-6-06 14:32:47"),"40");
        //var r = _timeLimitDomainService.CalcExpiredTime(DateTime.Parse("2024-02-29 10:12:33"), Share.Enums.FlowEngine.EFlowDirection.OrgToCenter, "10");
        //await _wfModuleDomainService.PersistenceModulesAsync(HttpContext.RequestAborted);

        //var rsp = await _daprClient.InvokeMethodAsync<ApiResponse<string>>(HttpMethod.Get, "identity", "api/v1/Test/time", HttpContext.RequestAborted);
        //var rsp1 = await _daprClient.InvokeMethodAsync<int, ApiResponse<string>>(HttpMethod.Post, "identity", "api/v1/Test/time1", 222, HttpContext.RequestAborted);
        //var a = await _trClient.QueryTelsAsync(new Tr.Sdk.Tels.QueryTelRequest() { }, HttpContext.RequestAborted);
        //await _daySettingRepository.IsWorkDay(DateTime.Now);

        //var r = _timeLimitDomainService.CalcWorkTime(DateTime.Parse("2024-6-06 14:32:47"), DateTime.Parse("2024-3-22 06:00:00"), false);
        //var r = _timeLimitDomainService.CalcWorkTime(DateTime.Parse("2024-3-24 17:20:00"), DateTime.Parse("2024-3-24 17:21:00"), false);
        //await _aiVisitService.QueryAiVisitTask(batchId, taskId, HttpContext.RequestAborted);
        //var r = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
        //var r = _timeLimitDomainService.CalcWorkTimeToDecimal(DateTime.Parse("2024-05-14 14:41:42"), DateTime.Parse("2024-05-14 14:50:46"), false);
        return OpenResponse.Ok(DateTime.Now.ToString("F"));
    }

    [HttpGet("pgsql")]
    public async Task<string> Pgsql()
    {
        var role = new Role
        {
            Name = $"test_role_{TimeOnly.FromDateTime(DateTime.Now)}",
            DisplayName = "test_role_display",
            ClientId = "test"
        };
        var roleId = await _roleRepository.AddAsync(role, HttpContext.RequestAborted);
        role.Description = "Description";
        await _roleRepository.UpdateAsync(role, HttpContext.RequestAborted);

        return roleId;
    }

    [AllowAnonymous]
    [HttpGet("roles")]
    public async Task<List<Role>> GetRoles()
    {
        using var lockManager = new LockManager(_distributedLock, $"{nameof(TestController)}.{nameof(GetRoles)}");
        lockManager.InvokeInLock(() => { Console.WriteLine("do something"); }, TimeSpan.FromSeconds(10));

        await lockManager.InvokeInLockAsync(
            d => _roleRepository.Queryable(includeDeleted: true).ToListAsync(),
            TimeSpan.FromSeconds(10),
            HttpContext.RequestAborted);

        var a = await _roleRepository.Queryable()
            //.Where(d => !d.IsDeleted)
            .ToListAsync();
        //var a = await db.Queryable<Role>().ToListAsync();

        var b = await _roleRepository.Queryable(includeDeleted: true).ToListAsync();
        return a;
    }

    //[AllowAnonymous]
    [HttpGet("hash")]
    public async Task Hash()
    {
        var s = _sessionContext;
    }


    /// <summary>
    /// signalR测试（method: Ring）
    /// </summary>
    /// <returns></returns>
    [HttpGet("ring")]
    public async Task RingTest()
    {
        await _realtimeService.RingAsync(_sessionContext.RequiredUserId,
            new RingDto { Id = new Guid().ToString(), From = _sessionContext.Phone ?? "未知号码", To = "12345" },
            HttpContext.RequestAborted);
    }

    /// <summary>
    /// signalR测试（method: Answered）
    /// </summary>
    /// <returns></returns>
    [HttpGet("answered")]
    public async Task AnsweredTest()
    {
        await _realtimeService.AnsweredAsync(_sessionContext.RequiredUserId,
            new AnsweredDto() { Id = new Guid().ToString(), From = _sessionContext.Phone ?? "未知号码", To = "12345" },
            HttpContext.RequestAborted);
    }

    /// <summary>
    /// signalR测试（method: Bye）
    /// </summary>
    /// <returns></returns>
    [HttpGet("bye")]
    public async Task ByeTest()
    {
        await _realtimeService.ByeAsync(_sessionContext.RequiredUserId, new ByeDto() { Id = new Guid().ToString() },
            HttpContext.RequestAborted);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    [AllowAnonymous]
    [HttpGet("t2")]
    public async Task GetVoiceEndAnswerAsyncTest()
    {
        //var answer = await _ivrDomainService.GetVoiceEndAnswerAsync("3", HttpContext.RequestAborted);
        //Console.WriteLine(answer.Content);
        throw new UserFriendlyException(2001, "test");
    }

    [HttpGet("wfdefine")]
    public async Task GetWorkflowDefine([FromQuery] string id)
    {
        //var query = _workflowTraceRepository.Queryable()
        //    .LeftJoin<Workflow>((t, w) => t.WorkflowId == w.Id)
        //    .LeftJoin<Order>((t, w, o) => w.ExternalId == o.Id)
        //    .Where((t, w, o) => o.No.Length == 14);

        //if (!string.IsNullOrEmpty(id))
        //    query = query.Where(d => d.WorkflowId == id);
        //var list = await query
        //    .Select((t, w, o) => new { t, w, o })
        //    .ToListAsync(HttpContext.RequestAborted);

        //var toUsers = list.Where(d => d.t.FlowAssignType == EFlowAssignType.User).ToList();
        //var userIds = toUsers.SelectMany(d => d.t.Handlers).Select(d => d.Key).Distinct().ToList();
        //var users = await _userRepository.Queryable()
        //    .Includes(d => d.Organization)
        //    .Where(d => userIds.Contains(d.Id))
        //    .ToListAsync(HttpContext.RequestAborted);
        ////var orgTraces = list.Where(d => d.FlowAssignType == EFlowAssignType.Org).ToList();
        //var stepHandlers = new List<WorkflowStepHandler>();
        //foreach (var toUser in toUsers)
        //{
        //    foreach (var traceHandler in toUser.t.Handlers)
        //    {
        //        var user = users.FirstOrDefault(d => d.Id == traceHandler.Key);
        //        if (user != null)
        //            stepHandlers.Add(new WorkflowStepHandler
        //            {
        //                WorkflowId = toUser.w.Id,
        //                ExternalId = toUser.w.ExternalId,
        //                WorkflowStepId = toUser.t.StepId,
        //                FlowAssignType = toUser.t.FlowAssignType.Value,
        //                UserId = user.Id,
        //                Username = user.Name,
        //                OrgId = user.OrgId,
        //                OrgName = user.Organization.Name,
        //                IsActualHandler = user.Id == toUser.t.HandlerId
        //            });
        //    }
        //}

        //var toOrgs = list.Where(d => d.t.FlowAssignType == EFlowAssignType.Org).ToList();
        //foreach (var toOrg in toOrgs)
        //{
        //    foreach (var handler in toOrg.t.Handlers)
        //    {
        //        stepHandlers.Add(new WorkflowStepHandler
        //        {
        //            WorkflowId = toOrg.w.Id,
        //            ExternalId = toOrg.w.ExternalId,
        //            WorkflowStepId = toOrg.t.StepId,
        //            FlowAssignType = toOrg.t.FlowAssignType.Value,
        //            OrgId = handler.Key,
        //            OrgName = handler.Value,
        //            IsActualHandler = handler.Key == toOrg.t.HandlerOrgId
        //        });
        //    }
        //}

        //_logger.LogInformation($"生成handlers: {stepHandlers.Count} 条");

        //await _workflowStepHandleRepository.AddRangeAsync(stepHandlers, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 处理FlowAssignType
    /// </summary>
    /// <returns></returns>
    [AllowAnonymous]
    [HttpPost("t3")]
    public async Task TestExportExcel()
    {
        var steps = await _workflowStepRepository.Queryable()
            .Includes(d => d.WorkflowTrace)
            .Where(d => SqlFunc.Exists(d.WorkflowTrace.Id) &&
                        d.FlowAssignType == null &&
                        SqlFunc.JsonArrayLength(d.Handlers) == 1)
            .ToListAsync(HttpContext.RequestAborted);
        //foreach (var step in steps)
        //{
        //    var handlerCount = step.Handlers.Count;
        //    if (handlerCount == 1)
        //    {
        //        step.FlowAssignType =
        //            step.Handlers.First().Key.Length == 36 ? EFlowAssignType.User : EFlowAssignType.Org;
        //        step.WorkflowTrace.FlowAssignType = step.FlowAssignType;
        //    }
        //    else if (handlerCount > 1)
        //    {

        //    }
        //    else
        //    {
        //        _logger.LogError($"无办理对象, {handlerCount}");
        //    }
        //}

        var list = new List<WorkflowStep>();
        foreach (var step in steps)
        {
            var handler = step.Handlers.First();
            if (string.IsNullOrEmpty(handler.Key)) continue;
            step.FlowAssignType =
                        handler.Key.Length == 36 ? EFlowAssignType.User : EFlowAssignType.Org;
            step.WorkflowTrace.FlowAssignType = step.FlowAssignType;
            list.Add(step);
        }

        await _workflowStepRepository
            .UpdateNav(list)
            .Include(d => d.WorkflowTrace)
            .ExecuteCommandAsync();
        //.UpdateRangeAsync(steps, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 赋值handlerId
    /// </summary>
    /// <returns></returns>
    [AllowAnonymous]
    [HttpPost("t4")]
    public async Task TestExportExcel1()
    {
        var steps = await _workflowStepRepository.Queryable()
            .Includes(d => d.WorkflowTrace)
            .Where(d => SqlFunc.Exists(d.WorkflowTrace.Id) &&
                        d.Status != EWorkflowStepStatus.Handled &&
                        d.HandlerId == null &&
                        d.FlowAssignType != null &&
                        SqlFunc.JsonArrayLength(d.Handlers) == 1)
            .ToListAsync(HttpContext.RequestAborted);

        var list = new List<WorkflowStep>();
        foreach (var step in steps)
        {
            var handler = step.Handlers.First();
            if (string.IsNullOrEmpty(handler.Key)) continue;
            if (step.FlowAssignType == EFlowAssignType.User)
            {
                step.HandlerId = handler.Key;
                step.HandlerName = handler.Value;
                step.WorkflowTrace.HandlerId = step.HandlerId;
                step.WorkflowTrace.HandlerName = step.HandlerName;
            }
            else
            {
                step.HandlerOrgId = handler.Key;
                step.HandlerOrgName = handler.Value;
                step.WorkflowTrace.HandlerOrgId = step.HandlerOrgId;
                step.WorkflowTrace.HandlerOrgName = step.HandlerOrgName;
            }
            list.Add(step);
        }

        await _workflowStepRepository
            .UpdateNav(list)
            .Include(d => d.WorkflowTrace)
            .ExecuteCommandAsync();
    }

    [HttpGet("rsa")]
    public async Task<string> Rsa()
    {
        var keyList = RsaKeyGenerator.Pkcs1Key(2048, true);
        var privateKey = keyList[0];
        var publicKey = keyList[1];
        return $"{publicKey} \r\n {privateKey}";
    }

}
