using System.Runtime.InteropServices;
using FortranWebApi.Models;
using System.Text.Json;
using System.Runtime.InteropServices.Marshalling;
using System.IO;

namespace FortranWebApi.Services
{
    public class FortranInteropService
    {
        // 静态构造函数设置DLL导入解析器
        static FortranInteropService()
        {
            // 添加当前目录到库搜索路径
            NativeLibrary.SetDllImportResolver(typeof(FortranInteropService).Assembly, (name, assembly, path) =>
            {
                if (name == "libSUB_SHUILIANGJISUAN.so")
                {
                    // 尝试从当前目录加载
                    string currentDir = Directory.GetCurrentDirectory();
                    string libraryPath = Path.Combine(currentDir, "libSUB_SHUILIANGJISUAN.so");
                    
                    if (File.Exists(libraryPath))
                    {
                        return NativeLibrary.Load(libraryPath);
                    }
                }
                
                // 回退到默认加载行为
                return IntPtr.Zero;
            });
        }

        // DllImport声明
        [DllImport("libSUB_SHUILIANGJISUAN.so", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SUB_SHUILIANGJISUAN")]
        private static extern void SUB_SHUILIANGJISUAN(
            ref int NDATA,
            ref float LONG,
            ref int INbd,
            ref int INzd,
            ref int INsm,
            ref int INrough,
            ref float ZZ0,
            ref int DB,
            float[] UQ,
            float[] DQH,
            ref float dt,
            float[] OUTT,
            float[] OUTQ,
            float[] OUTH
        );

        public string ProcessFortranRequest(string requestText)
        {
            try
            {
                // 解析请求
                var options = new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                    DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
                    PropertyNameCaseInsensitive = true,
                    WriteIndented = true
                };
                
                var request = JsonSerializer.Deserialize<FortranRequest>(requestText, options);
                if (request == null)
                {
                    throw new ArgumentException("无效的请求格式");
                }

                // 准备输入参数
                var parameters = request.Parameters;
                
                // 提取参数
                int NDATA = GetIntParameter(parameters, "NDATA");
                float LONG = GetFloatParameter(parameters, "LONG");
                int INbd = GetIntParameter(parameters, "INbd");
                int INzd = GetIntParameter(parameters, "INzd");
                int INsm = GetIntParameter(parameters, "INsm");
                int INrough = GetIntParameter(parameters, "INrough");
                float ZZ0 = GetFloatParameter(parameters, "ZZ0");
                int DB = GetIntParameter(parameters, "DB");
                float[] UQ = GetFloatArrayParameter(parameters, "UQ");
                float[] DQH = GetFloatArrayParameter(parameters, "DQH");
                float dt = GetFloatParameter(parameters, "dt");


                // 准备数组参数
                float[] OUTT = new float[10000]; // 输出数组,初始大小为10000
                float[] OUTQ = new float[10000]; // 输出数组,初始大小为10000
                float[] OUTH = new float[10000]; // 输出数组,初始大小为10000


                // 调用Fortran函数
                SUB_SHUILIANGJISUAN(
                    ref NDATA,
                    ref LONG,
                    ref INbd,
                    ref INzd,
                    ref INsm,
                    ref INrough,
                    ref ZZ0,
                    ref DB,
                    UQ,
                    DQH,
                    ref dt,
                    OUTT,
                    OUTQ,
                    OUTH
                );

                // 更新输出参数
                UpdateArrayParameter(parameters, "OUTT", OUTT);
                UpdateArrayParameter(parameters, "OUTQ", OUTQ);
                UpdateArrayParameter(parameters, "OUTH", OUTH);


                // 处理输出数组
                // 处理输出数组 OUTT
                // 注意:没有找到明确的长度参数,使用非零元素数量
                {
                    int nonZeroCount = 0;
                    for (int i = 0; i < OUTT.Length; i++)
                    {
                        if (OUTT[i] != 0) nonZeroCount = i + 1;
                    }
                    if (nonZeroCount > 0)
                    {
                        float[] resultArray = new float[nonZeroCount];
                        Array.Copy(OUTT, resultArray, nonZeroCount);
                        UpdateArrayParameter(parameters, "OUTT", resultArray);
                    }
                }
                // 处理输出数组 OUTQ
                // 注意:没有找到明确的长度参数,使用非零元素数量
                {
                    int nonZeroCount = 0;
                    for (int i = 0; i < OUTQ.Length; i++)
                    {
                        if (OUTQ[i] != 0) nonZeroCount = i + 1;
                    }
                    if (nonZeroCount > 0)
                    {
                        float[] resultArray = new float[nonZeroCount];
                        Array.Copy(OUTQ, resultArray, nonZeroCount);
                        UpdateArrayParameter(parameters, "OUTQ", resultArray);
                    }
                }
                // 处理输出数组 OUTH
                // 注意:没有找到明确的长度参数,使用非零元素数量
                {
                    int nonZeroCount = 0;
                    for (int i = 0; i < OUTH.Length; i++)
                    {
                        if (OUTH[i] != 0) nonZeroCount = i + 1;
                    }
                    if (nonZeroCount > 0)
                    {
                        float[] resultArray = new float[nonZeroCount];
                        Array.Copy(OUTH, resultArray, nonZeroCount);
                        UpdateArrayParameter(parameters, "OUTH", resultArray);
                    }
                }


                // 返回结果 - 只返回原始请求的结构,但包含更新后的参数
                var result = new FortranRequest
                {
                    FuncName = request.FuncName,
                    ClassName = request.ClassName,
                    Parameters = parameters
                };
                
                return JsonSerializer.Serialize(result, options);
            }
            catch (Exception ex)
            {
                return JsonSerializer.Serialize(new { error = ex.Message });
            }
        }

        private float GetFloatParameter(List<FortranParameter> parameters, string name)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param == null || param.Data == null)
            {
                return 0.0f;
            }
            
            if (param.Data is JsonElement element)
            {
                if (element.ValueKind == JsonValueKind.Number)
                {
                    return element.GetSingle();
                }
            }
            
            return Convert.ToSingle(param.Data);
        }
        private double GetDoubleParameter(List<FortranParameter> parameters, string name)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param == null || param.Data == null)
            {
                return 0.0;
            }

            if (param.Data is JsonElement element)
            {
                if (element.ValueKind == JsonValueKind.Number)
                {
                    return element.GetSingle();
                }
            }

            return Convert.ToDouble(param.Data);
        }
        private int GetIntParameter(List<FortranParameter> parameters, string name)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param == null || param.Data == null)
            {
                return 0;
            }
            
            if (param.Data is JsonElement element)
            {
                if (element.ValueKind == JsonValueKind.Number)
                {
                    return element.GetInt32();
                }
            }
            
            return Convert.ToInt32(param.Data);
        }
        private int[] GetIntArrayParameter(List<FortranParameter> parameters, string name)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param == null || param.Data == null)
            {
                return Array.Empty<int>();
            }

            if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
            {
                var array = new List<int>();
                foreach (var item in element.EnumerateArray())
                {
                    if (item.ValueKind == JsonValueKind.Number)
                    {
                        array.Add(item.GetInt32());
                    }
                }
                return array.ToArray();
            }

            if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
            {
                var array = new List<int>();
                foreach (var item in enumerable)
                {
                    array.Add(Convert.ToInt32(item));
                }
                return array.ToArray();
            }

            return Array.Empty<int>();
        }
        private float[] GetFloatArrayParameter(List<FortranParameter> parameters, string name)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param == null || param.Data == null)
            {
                return Array.Empty<float>();
            }
            
            if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
            {
                var array = new List<float>();
                foreach (var item in element.EnumerateArray())
                {
                    if (item.ValueKind == JsonValueKind.Number)
                    {
                        array.Add(item.GetSingle());
                    }
                }
                return array.ToArray();
            }
            
            if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
            {
                var array = new List<float>();
                foreach (var item in enumerable)
                {
                    array.Add(Convert.ToSingle(item));
                }
                return array.ToArray();
            }
            
            return Array.Empty<float>();
        }
        private double[] GetDoubleArrayParameter(List<FortranParameter> parameters, string name)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param == null || param.Data == null)
            {
                return Array.Empty<double>();
            }

            if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
            {
                var array = new List<double>();
                foreach (var item in element.EnumerateArray())
                {
                    if (item.ValueKind == JsonValueKind.Number)
                    {
                        array.Add(item.GetSingle());
                    }
                }
                return array.ToArray();
            }

            if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
            {
                var array = new List<double>();
                foreach (var item in enumerable)
                {
                    array.Add(Convert.ToSingle(item));
                }
                return array.ToArray();
            }

            return Array.Empty<double>();
        }
        private void UpdateParameter(List<FortranParameter> parameters, string name, object value)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param != null)
            {
                param.Data = value;
            }
        }

        private void UpdateArrayParameter(List<FortranParameter> parameters, string name, float[] value)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param != null)
            {
                param.Data = value;
            }
        }
        private void UpdateDoubleArrayParameter(List<FortranParameter> parameters, string name, double[] value)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param != null)
            {
                param.Data = value;
            }
        }
        private void UpdateIntArrayParameter(List<FortranParameter> parameters, string name, int[] value)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param != null)
            {
                param.Data = value;
            }
        }
        // 添加新的辅助方法来处理二维数组
        private double[,] GetDouble2DArrayParameter(List<FortranParameter> parameters, string name, int rows, int cols)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param == null || param.Data == null)
            {
                return new double[rows, cols];
            }

            double[,] result = new double[rows, cols];

            if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
            {
                int index = 0;
                foreach (var item in element.EnumerateArray())
                {
                    if (item.ValueKind == JsonValueKind.Number)
                    {
                        int row = index / cols;
                        int col = index % cols;
                        if (row < rows && col < cols)
                        {
                            result[row, col] = item.GetDouble();
                        }
                        index++;
                    }
                }
            }
            else if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
            {
                int index = 0;
                foreach (var item in enumerable)
                {
                    int row = index / cols;
                    int col = index % cols;
                    if (row < rows && col < cols)
                    {
                        result[row, col] = Convert.ToDouble(item);
                    }
                    index++;
                }
            }

            return result;
        }

        // 添加更新二维数组参数的方法
        private void UpdateDouble2DArrayParameter(List<FortranParameter> parameters, string name, double[,] value)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param != null)
            {
                // 将二维数组转换为一维数组以便于JSON序列化
                int rows = value.GetLength(0);
                int cols = value.GetLength(1);
                double[] flatArray = new double[rows * cols];
                for (int i = 0; i < rows; i++)
                {
                    for (int j = 0; j < cols; j++)
                    {
                        flatArray[i * cols + j] = value[i, j];
                    }
                }
                param.Data = flatArray;
            }
        }
        // float版本
        private float[,] GetFloat2DArrayParameter(List<FortranParameter> parameters, string name, int rows, int cols)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param == null || param.Data == null)
            {
                return new float[rows, cols];
            }

            float[,] result = new float[rows, cols];

            if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
            {
                int index = 0;
                foreach (var item in element.EnumerateArray())
                {
                    if (item.ValueKind == JsonValueKind.Number)
                    {
                        int row = index / cols;
                        int col = index % cols;
                        if (row < rows && col < cols)
                        {
                            result[row, col] = item.GetSingle();
                        }
                        index++;
                    }
                }
            }
            else if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
            {
                int index = 0;
                foreach (var item in enumerable)
                {
                    int row = index / cols;
                    int col = index % cols;
                    if (row < rows && col < cols)
                    {
                        result[row, col] = Convert.ToSingle(item);
                    }
                    index++;
                }
            }

            return result;
        }

        private void UpdateFloat2DArrayParameter(List<FortranParameter> parameters, string name, float[,] value)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param != null)
            {
                int rows = value.GetLength(0);
                int cols = value.GetLength(1);
                float[] flatArray = new float[rows * cols];
                for (int i = 0; i < rows; i++)
                {
                    for (int j = 0; j < cols; j++)
                    {
                        flatArray[i * cols + j] = value[i, j];
                    }
                }
                param.Data = flatArray;
            }
        }

        // int版本
        private int[,] GetInt2DArrayParameter(List<FortranParameter> parameters, string name, int rows, int cols)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param == null || param.Data == null)
            {
                return new int[rows, cols];
            }

            int[,] result = new int[rows, cols];

            if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
            {
                int index = 0;
                foreach (var item in element.EnumerateArray())
                {
                    if (item.ValueKind == JsonValueKind.Number)
                    {
                        int row = index / cols;
                        int col = index % cols;
                        if (row < rows && col < cols)
                        {
                            result[row, col] = item.GetInt32();
                        }
                        index++;
                    }
                }
            }
            else if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
            {
                int index = 0;
                foreach (var item in enumerable)
                {
                    int row = index / cols;
                    int col = index % cols;
                    if (row < rows && col < cols)
                    {
                        result[row, col] = Convert.ToInt32(item);
                    }
                    index++;
                }
            }

            return result;
        }

        private void UpdateInt2DArrayParameter(List<FortranParameter> parameters, string name, int[,] value)
        {
            var param = parameters.FirstOrDefault(p => p.Name == name);
            if (param != null)
            {
                int rows = value.GetLength(0);
                int cols = value.GetLength(1);
                int[] flatArray = new int[rows * cols];
                for (int i = 0; i < rows; i++)
                {
                    for (int j = 0; j < cols; j++)
                    {
                        flatArray[i * cols + j] = value[i, j];
                    }
                }
                param.Data = flatArray;
            }
        }
    }
}