using Fw.Utility.UnifyResponse;
using Hotline.Caching.Interfaces;
using Hotline.Settings;
using Hotline.Share.Dtos.File;
using Hotline.Share.Enums.Article;
using Hotline.Share.Tools;
using Microsoft.Extensions.Logging;
using Renci.SshNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Runtime.InteropServices.JavaScript;
using System.Security.Policy;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using XF.Domain.Dependency;

namespace Hotline.File;
public class FileDomainService : IFileDomainService, IScopeDependency
{
    private readonly ISystemSettingCacheManager _setting;
    private readonly ILogger<FileDomainService> _logger;
    private readonly IFileRepository _fileRepository;
    private readonly ISystemLogRepository _systemLogRepository;

    public FileDomainService(ISystemSettingCacheManager setting, ILogger<FileDomainService> logger, IFileRepository fileRepository, ISystemLogRepository systemLogRepository)
    {
        _setting = setting;
        _logger = logger;
        _fileRepository = fileRepository;
        _systemLogRepository = systemLogRepository;
    }

    /// <summary>
    /// 下载网络文件并上传到文件服务器, 返回 File.Id
    /// </summary>
    /// <param name="file"></param>
    /// <param name="key"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<string> GetNetworkFileAsync(string file, string key, CancellationToken cancellationToken = default)
    {
        try
        {
            var fileBytes = await DownloadFileToMemoryAsync(file);
            if (fileBytes is null) return string.Empty;

            var uploadUrl = _setting.FileServerUrl + "/file/upload?source=hotline";
            var match = Regex.Match(file, "[^/]+\\.[a-zA-Z0-9]+$").Value;
            var resultJson = await UploadFileFromMemoryAsync(fileBytes, match, uploadUrl);
            var result = resultJson.FromJson<ApiResponse<FileJson>>();
            var fileSplit = match.Split('.');
            var entity = new File()
            {
                Key = key,
                Additions = result.Result.Id,
                FileName = result.Result.FileName,
                Path = result.Result.Path,
                AllPath = file,
                Type = fileSplit[1],
                Name = fileSplit[0],
            };
            entity.Id = await _fileRepository.AddAsync(entity);
            return entity.Id;
        }
        catch (Exception e)
        {
            var message = $"下载网络文件并上传到文件服务器失败: {e.Message}";
            _logger.LogError(message + e.ToJson());
            _systemLogRepository.Add("下载网络附件", key, message);
        }
        return string.Empty;
    }

    /// <summary>
    /// 下载文件, 返回字节
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    private async Task<byte[]> DownloadFileToMemoryAsync(string url)
    {
#if DEBUG
        var uri = new Uri(url);
        var _sshClient = new SshClient("171.94.154.2", 22, "root", "ZGbyy@2024!");
        _sshClient.Connect();
        var forwardedPort = new ForwardedPortLocal("127.0.0.1", 8090, uri.Host, (uint)uri.Port);
        _sshClient.AddForwardedPort(forwardedPort);
        forwardedPort.Start();
        url = "http://127.0.0.1:8090" + uri.AbsolutePath;
#endif
        try
        {
            using var client = new HttpClient();
            HttpResponseMessage response = await client.GetAsync(url);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsByteArrayAsync();

        }
        catch (Exception e)
        {
            _logger.LogError("保存第三方系统的文件失败:" + e.Message);
        }
        finally
        {
#if DEBUG
            if (_sshClient.IsConnected)
            {
                _sshClient.Disconnect();
            }
#endif
        }
        return null;
    }

    public async Task<string> UploadFileFromMemoryAsync(byte[] fileBytes, string fileName, string uploadUrl, string contentType = "image/jpeg")
    {
        using HttpClient client = new HttpClient();
        using var multipartContent = new MultipartFormDataContent();
        var fileContent = new ByteArrayContent(fileBytes);
        fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType);

        multipartContent.Add(fileContent, "fileData", fileName);

        HttpResponseMessage response = await client.PostAsync(uploadUrl, multipartContent);
        response.EnsureSuccessStatusCode();

        var result = await response.Content.ReadAsStringAsync();
        return result;
    }

    public async Task<FileJson> UploadFileFromMemoryAsync(Stream fileStream, string fileName, EFileType fileType)
    {
        var fileByte =  await fileStream.ToByteArrayAsync();
        var uploadUrl = _setting.FileServerUrl + "/file/upload?source=hotline";
        return (await UploadFileFromMemoryAsync(fileByte, fileName, uploadUrl, fileType.GetContentType())).FromJson<ApiResponse<FileJson>>().Result;
    }
}

