using AipGateway.AIP;
using AipGateway.API.Service.Models;
using AipGateway.API.Service.Services;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Buffers.Text;
using System.IO;
using System.Net;
using System.Text;
using static AipGateway.API.Service.Models.ReqFileInfo;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using AipGateway.API.Service.Utils;
using Microsoft.AspNetCore.Http.HttpResults;
using AipGateway.Data;
using AipGateway.Data.Entities;
using System.Reflection.Metadata.Ecma335;
using Microsoft.EntityFrameworkCore;

namespace AipGateway.API.Service.Controllers
{
    [ApiController]

    [Route("v1/aip-files")]
    //[Route("v1/[controller]")]
    public class AipFileController : ControllerBase
    {
        private Microsoft.AspNetCore.Http.IHttpContextAccessor _accessor = null;
        private readonly ILogger<AipFileController> _logger = null;
        private readonly IAipFileManagerService _aipFileService = null;
        private readonly AipDbContext _aipDb = null;

        public AipFileController(Microsoft.AspNetCore.Http.IHttpContextAccessor accessor, 
            ILogger<AipFileController> logger, 
            IAipFileManagerService aipFileService,
            AipDbContext aipDb)
        {
            _accessor = accessor;
            _logger = logger;
            _aipFileService = aipFileService;
            _aipDb = aipDb;
            _logger.LogError("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: AipFileController");
        }

        private string GetRequestIpAddress()
        {
            string remoteIpAddress = "";
            if (_accessor.HttpContext.Request.Headers != null)
            {
                //XFF(X-Forwarded-For) HTTP 헤더 필드는 클라이언트의 원래 IP 주소를 식별하기 위한 표준
                //HTTP 프록시 또는 로드 밸런서를 통해 웹 서버에 연결

                var forwardedHeader = _accessor.HttpContext.Request.Headers["X-Forwarded-For"];
                if (!Microsoft.Extensions.Primitives.StringValues.IsNullOrEmpty(forwardedHeader))
                {
                    remoteIpAddress = forwardedHeader.FirstOrDefault();
                }
            }

            //헤더가 없는 경우 연결 원격 IP 주소를 가져오기
            if (string.IsNullOrEmpty(remoteIpAddress) && _accessor.HttpContext.Connection.RemoteIpAddress != null)
            {
                remoteIpAddress = _accessor.HttpContext.Connection.RemoteIpAddress.ToString();
            }
            
            remoteIpAddress = remoteIpAddress.Replace("::1", "192.168.0.1").Replace("::ffff:", "");
            return remoteIpAddress;
        }

        [HttpGet("linked-systems")]
        [Produces("application/json")]
        public async Task<IEnumerable<TbLinkedSystem>> GetLinkedSystems()
        {
            var linkedSystems = await _aipDb.LinkedSystems.ToListAsync();
            var linkedServers = await _aipDb.LinkedServers.ToListAsync();
            var linkedDecryptKeys = await _aipDb.LinkedDecryptKeys.ToListAsync();
            var linkedApiKeys = await _aipDb.LinkedApiKeys.ToListAsync();

            var aipLabels = await _aipDb.AipLabels.ToListAsync();
            var aipPolicies = await _aipDb.AipPolicies.ToListAsync();
            var aipProtections = await _aipDb.AipProtections.ToListAsync();
            
            var aipServers = await _aipDb.AipServers.ToListAsync();
            var aipConfig = await _aipDb.AipConfigs.ToListAsync();

            _logger.LogInformation("   linkedSystems: {0} EA.", linkedSystems.Count);
            foreach (var v in linkedSystems)
            {
                _logger.LogInformation("   linkedSystems: {0}", v.ToString());
            }
            _logger.LogInformation("   linkedServers: {0} EA.", linkedServers.Count);
            foreach (var v in linkedServers)
            {
                _logger.LogInformation("   linkedServers: {0}", v.ToString());
            }
            _logger.LogInformation("linkedDecryptKeys: {0} EA.", linkedDecryptKeys.Count);
            foreach (var v in linkedDecryptKeys)
            {
                _logger.LogInformation("linkedDecryptKeys: {0}", v.ToString());
            }
            _logger.LogInformation("    linkedApiKeys: {0} EA.", linkedApiKeys.Count);
            foreach (var v in linkedApiKeys)
            {
                _logger.LogInformation("    linkedApiKeys: {0}", v.ToString());
            }

            _logger.LogInformation("     aipLabels: {0} EA.", aipLabels.Count);
            foreach (var v in aipLabels)
            {
                _logger.LogInformation("     aipLabels: {0}", v.ToString());
            }
            _logger.LogInformation("   aipPolicies: {0} EA.", aipPolicies.Count);
            foreach (var v in aipPolicies)
            {
                _logger.LogInformation("   aipPolicies: {0}", v.ToString());
            }
            _logger.LogInformation("aipProtections: {0} EA.", aipProtections.Count);
            foreach (var v in aipProtections)
            {
                _logger.LogInformation("aipProtections: {0}", v.ToString());
            }


            _logger.LogInformation("aipServers: {0} EA.", aipServers.Count);
            foreach (var v in aipServers)
            {
                _logger.LogInformation("aipServers: {0}", v.ToString());
            }
            _logger.LogInformation(" aipConfig: {0} EA.", aipConfig.Count);
            foreach (var v in aipConfig)
            {
                _logger.LogInformation(" aipConfig: {0}", v.ToString());
            }

            return linkedSystems;
        }

        [HttpGet("ip-address")]
        [Produces("application/json")]
        public Task<IpAddress> GetIpAddress()
        {
            string ipAddress = "";
            //IHeaderDictionary header = Request.HttpContext.Request.Headers;
            //foreach (KeyValuePair<string, StringValues> item in header)
            //{
            //_logger.LogInformation("{0}", item.ToString());
            //}

            //_logger.LogInformation(" HTTP_X_FORWARDED_FOR: {0}", HttpContext.GetServerVariable("HTTP_X_FORWARDED_FOR"));
            //_logger.LogInformation("            Forwarded: {0}", HttpContext.GetServerVariable("Forwarded"));
            //_logger.LogInformation("      X-Forwarded-For: {0}", HttpContext.GetServerVariable("X-Forwarded-For"));
            //_logger.LogInformation("      X-FORWARDED-FOR: {0}", HttpContext.GetServerVariable("X-FORWARDED-FOR"));
            //_logger.LogInformation("X-Forwarded-Client-Ip: {0}", HttpContext.GetServerVariable("X-Forwarded-Client-Ip"));
            //_logger.LogInformation("           user-agent: {0}", HttpContext.GetServerVariable("user-agent"));
            //_logger.LogInformation("      Proxy-Client-IP: {0}", HttpContext.GetServerVariable("Proxy-Client-IP"));
            //_logger.LogInformation("   WL-Proxy-Client-IP: {0}", HttpContext.GetServerVariable("WL-Proxy-Client-IP"));
            _logger.LogInformation("          REMOTE_ADDR: {0}", Microsoft.AspNetCore.Http.HttpContextServerVariableExtensions.GetServerVariable(HttpContext, "REMOTE_ADDR"));

            ipAddress = GetRequestIpAddress();


            //IPHelper.GetSourceIp(Request);
            //string ipAddress2 = Request.HttpContext.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            //string temp = "";
            //if (!string.IsNullOrEmpty(ipAddress2))
            //{
            //    string[] addresses = ipAddress2.Split(',');
            //    if (addresses.Length != 0)
            //    {
            //        temp = addresses[0];
            //    }
            //}
            //temp = context.Request.ServerVariables["REMOTE_ADDR"];

            //IPAddress remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress;
            //if (remoteIpAddress != null)
            //{
            //    _logger.LogInformation("RemoteIpAddress_1: {0}", remoteIpAddress.ToString());
            //    if (remoteIpAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
            //    {
            //        _logger.LogInformation("RemoteIpAddress_2: Looking for DNS");
            //        remoteIpAddress = System.Net.Dns.GetHostEntry(remoteIpAddress)
            //            .AddressList
            //            .First(x => x.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
            //    }
            //    ipAddress = remoteIpAddress.ToString();
            //}
            //else
            //{
            //    _logger.LogInformation("RemoteIpAddress_3: Unknown");
            //}

            _logger.LogInformation("RemoteIpAddress_4: {0}", ipAddress);

            return Task.FromResult(new IpAddress()
            {
                ipAddress = ipAddress
            });
        }

        [HttpGet("config")]
        [Produces("application/json")]
        public async Task<AipConfig> GetConfig()
        {
            try
            {
                return await _aipFileService.GetConfig();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "AipFileController::GetConfig.");
                return null;
            }
        }
        [HttpGet("aip-config")]
        [Produces("application/json")]
        public async Task<List<TbAipConfig>> GetAipConfig()
        {
            try
            {
                return await _aipDb.AipConfigs.ToListAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "AipFileController::GetAipConfig.");
                return null;
            }
        }
        [HttpGet("labels")]
        [Produces("application/json")]
        public async Task<List<AipLabel>?> GetLabels()
        {
            try
            {
                return await _aipFileService.GetLabels();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "AipFileController::GetLabels.");
                return null;
            }
        }

        [HttpGet("policies")]
        [Produces("application/json")]
        public async Task<List<AipLabel>?> GetPolicies()
        {
            try
            {
                return await _aipFileService.GetPolicies();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "AipFileController::GetPolicies.");
                return null;
            }
        }

        [HttpGet("protections")]
        [Produces("application/json")]
        public async Task<List<AipTemplate>?> GetProtections()
        {
            try
            {
                return await _aipFileService.GetProtections();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "AipFileController::GetProtections.");
                return null;
            }
        }

        [HttpGet("file-info")]
        [Produces("application/json")]
        public async Task<AipFileInfo> GetFileInfo([FromQuery] ReqFileInfo.ByFileName file)
        {
            try
            {
                return await _aipFileService.GetFileInfo(file.name);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "AipFileController::GetFileInfo-byFileName.");
                return null;
            }
        }

        [HttpPost("stream-info")]
        [Produces("application/json")]
        public async Task<AipFileInfo> GetStreamInfo([FromBody] ReqFileInfo.ByStream file)
        {
            try
            {
                //string base64String = Encoding.Default.GetString(file.stream);
                //Console.WriteLine("0.::::: {0}", file.fileData);
                //string str1 = Encoding.UTF8.GetString(file.stream);
                //Console.WriteLine("0.::::: {0}", str1);
                using (var stream = new MemoryStream(Convert.FromBase64String(file.fileData))) {
                    return await _aipFileService.GetFileInfo(stream);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "AipFileController::GetFileInfo-byFileStream.");
                return null;
            }
        }

        [HttpGet("file-data")]
        [Produces("application/json")]
        public FileData GetFileData ([FromQuery] ReqFileInfo.ByFileName file)
        {
            FileData result = new FileData();
            try
            {
                //Console.WriteLine("0.::::::::::::::::::::::::::::::::::::::::::::::::::::::: {0}", file.name);
                if (System.IO.File.Exists(file.name))
                {
                    using (FileStream fs = System.IO.File.OpenRead(file.name))
                    {
                        using (var reader = new BinaryReader(fs))
                        {
                            result.byteDataArr = reader.ReadBytes((int)fs.Length);
                            result.base64Data = Convert.ToBase64String(result.byteDataArr);
                            //result.streamData = new MemoryStream();
                            //result.streamData.Write(result.byteDataArr, 0, result.byteDataArr.Length);
                        }

                        var bytes = Convert.FromBase64String(result.base64Data);
                        var contents = new StreamContent(new MemoryStream(bytes));
                        //Console.WriteLine("{0}", contents);
                        var stream = new MemoryStream(Convert.FromBase64String(result.base64Data));

                        if (file.name.Contains(".txt"))
                        {
                            System.IO.File.WriteAllBytes(@"c:\data\sample.txt.txt", Convert.FromBase64String(result.base64Data));
                        }
                        else
                        {
                            System.IO.File.WriteAllBytes(@"c:\data\sample.txt.pptx", Convert.FromBase64String(result.base64Data));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //Console.WriteLine("{0}", ex.Message);
                _logger.LogError(ex, "AipFileController::GetFileData.");
            }
            return result;
        }

    }
}
