using dataladder.AddressVerification;
using dataladder.Data;
using dataladder.Data.DataTransformation;
using dataladder.IO;
using dataladder.Matching.Project;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SdkInterface
{
    public class ApiSource
    {
        private string _dataPath;
        DataSourceInfo dsi;
        private string workingFolder;
        private List<string> variables;

        public string Name => dsi.Name;

        /// <summary>
        /// Results of transformation
        /// if it is null, this means transformation is not executed
        /// </summary>
        public DataTable TransformedValues
        {
            get
            {
                if (dsi == null)
                    return null;

                return OnDriveTableToDatatTable(dsi.TransformedValuesTable);
            }
        }

        public ApiSource(string sourceName, string workingFolder, string[] columnData, string[] columnName = null)
        {
            _dataPath = workingFolder;
            IOHelper.CreateDirectoryIfNotExist(_dataPath);
            var uncompliteFolder = System.IO.Path.Combine(_dataPath, "uncomplete");
            IOHelper.CreateDirectoryIfNotExist(uncompliteFolder);

            OnDriveTable drt = new OnDriveTable(operationMode: OperationModes.Memory);
            for (int i = 0; i < columnData.Length; i++)
            {
                var name = $"Col{i}";
                if (columnName != null)
                    if (i < columnName.Length)
                        name = columnName[i];
                drt.AddField(name, "".GetType());
                drt.SetData(columnData[i], 0, name);
            }
            drt.Name = sourceName;

            AddressVerificationSettings avs = new AddressVerificationSettings();

            dsi = new DataSourceInfo(null, avs, _dataPath);
            dsi.InputTable = drt;
        }
        
        public ApiSource(string sourceName, string dataPath, DataTable newTable)
        {
            _dataPath = dataPath;
            IOHelper.CreateDirectoryIfNotExist(_dataPath);
            var uncompliteFolder = System.IO.Path.Combine(_dataPath, "uncomplete");
            IOHelper.CreateDirectoryIfNotExist(uncompliteFolder);

            AddressVerificationSettings avs = new AddressVerificationSettings();

            dsi = new DataSourceInfo(null, avs, _dataPath);

            dsi.InputTable = CreateOnDriveTableWithStringColumns(newTable, sourceName);
        }

        public void SetTransformations(List<ApiTransformation> transform)
        {
            for (int i = 0; i < dsi.ColumnTransformationList.Count; i++)
            {
                string name = ((ColumnTransformation)dsi.ColumnTransformationList[i]).FieldName;
                for (int j = 0; j < transform.Count; j++)
                {
                    if (name.Equals(transform[j].ColumnName))
                    {
                        FillColumnTransformation((ColumnTransformation)dsi.ColumnTransformationList[i], transform[j]);
                    }
                }
            }
        }

        private void FillColumnTransformation(ColumnTransformation columnTransformation, ApiTransformation apiTransformation)
        {
            TransformationTypes type = TransformationTypes.None;
            if (apiTransformation.TransformationType != ColumnExtraction.None)
            {
                type = ApiTransformation.ConvertFromColumnExtraction(apiTransformation.TransformationType);
            }
            columnTransformation.TransformationType = type;
        }

        public void RunTransformation(Modes operationMode = Modes.Memory)
        {
            OperationModes mode = operationMode == Modes.Disk ? OperationModes.Disk : OperationModes.Memory;
            dsi.CreateDiagram(operationMode: mode);
            dsi.RunTransformation(mode);
        }

        private OnDriveTable CreateOnDriveTableWithStringColumns(System.Data.DataTable table, string newName)
        {
            OnDriveTable res = new OnDriveTable(operationMode: OperationModes.Memory);
            for (int i = 0; i < table.Columns.Count; i++)
            {
                var col = table.Columns[i];
                res.AddField(col.ColumnName, "".GetType());
            }
            for (int i = 0; i < table.Rows.Count; i++)
            {
                var row = table.Rows[i];
                for (int j = 0; j < table.Columns.Count; j++)
                {
                    string colName = table.Columns[j].ColumnName;
                    res.SetData(row[colName]?.ToString() ?? "", i, colName);
                }
            }
            res.Name = newName;
            return res;
        }

        private DataTable OnDriveTableToDatatTable(ITable2CoordsMapper drive)
        {
            if (drive == null)
                return null;

            DataTable dt = new DataTable(drive.Name);
            for (int i = 0; i < drive.ColumnCount; i++)
            {
                dt.Columns.Add(drive.GetColumnName(i), drive.GetField(i).Type);
            }
            for (int i = 0; i < drive.RecordCount; i++)
            {
                DataRow row = dt.NewRow();
                for (int j = 0; j < drive.ColumnCount; j++)
                {
                    row[j] = drive.GetData(i, j);
                }
                dt.Rows.Add(row);
            }
            return dt;
        }
    }

    public enum Modes
    {
        Disk,
        Memory,
    }

    public class SdkHelper
    {
        public static DataTable MultiArrayToDataTable(string[,] arr, string[] columnNames = null, string tableName = null)
        {
            if (tableName == null)
            {
                tableName = $"Table-{Guid.NewGuid()}";
            }

            int cols = arr.GetLength(0);
            int rows = arr.GetLength(1);
            List<string> names = new List<string>(columnNames);
            if (names.Count < cols)
            {
                for (int i = names.Count; i < cols; i++)
                {
                    names.Add($"Col{i}");
                }
            }

            DataTable dt = new DataTable(tableName);
            for (int i = 0; i < cols; i++)
            {
                dt.Columns.Add(names[i], typeof(string));
            }
            for (int i = 0; i < rows; i++)
            {
                DataRow row = dt.NewRow();
                for (int j = 0; j < cols; j++)
                {
                    row[j] = arr[i, j];
                }
                dt.Rows.Add(row);
            }

            return dt;
        }
    }
}
