using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using dataladder.Data;
using LiveSearchDemo.Contracts;
using LiveSearchDemo.Entities;
using SampleServiceNamespace;

namespace LiveSearchDemo.Presenters
{
    class MainFormPresenter : IPresenter
    {
        private const String EngineConfigurationIniFileName = "configuration.ini";
        private const String ProjectsIniFileName = "projects.ini";

        private readonly IView _view;

        private EngineWrapper _engineWrapper;
        private readonly IniParser _projectsParser;

        private readonly String _appPath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);

        private double? _matchLevel = 80.0;
        private double? _filterLevel = 90.0;

        #region Constructors

        public MainFormPresenter(IView view)
        {
            _view = view;

            if (!System.IO.File.Exists(ProjectsIniFileName))
            {
                System.IO.File.Create(ProjectsIniFileName);
            }

            string fullIniName = System.IO.Path.Combine(_appPath, ProjectsIniFileName);
            _projectsParser = new IniParser(fullIniName);
        }

        #endregion

        #region IPresenter implementation

        public void LoadProjectsPath()
        {
            String iniFilePath = System.IO.Path.Combine(_appPath, EngineConfigurationIniFileName);
            IniParser parser = new IniParser(iniFilePath);

            _view.ProjectsPath = parser.GetSetting("AppSettings", "projectsPath");
        }

        public void LoadProject()
        {
            if (_engineWrapper != null)
            {
                _engineWrapper.Dispose();
                _engineWrapper = null;
            }

            _engineWrapper = new EngineWrapper(projectName:_view.Project.Name, useCache:true);

            _view.Project.Criteria = _engineWrapper.MatchingFieldNames.Select(mfn => new Criteria() { FieldName = mfn, Threshold = 90 }).ToList();
            _view.CleansedTable = _engineWrapper.GetUnitedTable();
            _view.BindProjectInfo();
        }

        public void LoadSavedSearchValues()
        {
            Dictionary<String, String> savedValues = new Dictionary<String, String>();
            foreach (var criteria in _view.Project.Criteria)
            {
                savedValues.Add(criteria.FieldName, _projectsParser.GetSetting(_view.Project.Name, criteria.FieldName));
            }
            _view.BindSavedSearchValues(savedValues);
        }

        public void SaveSearchValues()
        {
            for (int i = 0; i < _view.SearchValues.Length; i++)
            {
                string value = _view.SearchValues[i];
                _projectsParser.AddSetting(_view.Project.Name, _engineWrapper.MatchingFieldNames[i], value);
            }
            _projectsParser.SaveSettings();
        }

        public TimeSpan PerformLiveSearch()
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            _view.LiveSearchResultsTable = _engineWrapper.FindMatches(_view.Project.Name, _view.SearchValues, _view.BestMatchesCapacity);
            sw.Stop();

            _view.IsInputDataColumn = _engineWrapper.IsInputDataColumn;
            _view.BindSearchResults();

            return sw.Elapsed;
        }

        public void CheckForDuplicates()
        {
            if (_view.InputValues.All(value => String.IsNullOrWhiteSpace(value)))
            {
                _view.DuplicatesTable = null;
                _view.BindDuplicateCheckResults();
                return;
            }

            _view.DuplicatesTable = _engineWrapper.FindMatches(_view.Project.Name, _view.InputValues, 10000);
            _view.IsInputDataColumn = _engineWrapper.IsInputDataColumn;
            _view.BindDuplicateCheckResults();
        }

        public void InsertRecord()
        {
            string error;
            System.Data.DataTable insertedData;
            //_engineWrapper.InsertRecord("apiDemoDb", _view.InputValues, out error);
            var fieldNames = _view.Project.Criteria.Select(c => c.FieldName).ToArray();

            _engineWrapper.InsertRecord(fieldNames, _view.InputValues, out insertedData, out error);
            if (String.IsNullOrEmpty(error))
            {
                if (insertedData?.Rows.Count == 1)
                {
                    _engineWrapper.AddToCacheTableRecord(insertedData);
                    _view.InsertedTable = CreateInMemoryTableWithStringColumns(insertedData, "AddedRecords");
                    _view.BindInsertedTable();
                }
                else
                    _engineWrapper.AddToCacheTableRecordWithOnlyMatchedFields(_view.InputValues);
                _view.CleansedTable = _engineWrapper.GetUnitedTable();
                _view.BindCleansedTable();
            }
            else
            {
                _view.DisplayError(error);
            }
        }

        public void SetThresholds(double highLevel, double lowLevel)
        {
            _matchLevel = lowLevel;
            _filterLevel = highLevel;
            _engineWrapper?.SetThreshold(_matchLevel.Value);
        }

        #endregion

        #region Helpers
        private InMemoryTable CreateInMemoryTableWithStringColumns(System.Data.DataTable table, string newName)
        {
            InMemoryTable res = new InMemoryTable(newName);
            for (int i = 0; i < table.Columns.Count; i++)
            {
                var col = table.Columns[i];
                res.AddField(col.ColumnName, "".GetType());
                Console.WriteLine(col.ColumnName + " - " +col.DataType);
            }
            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;

                    Console.WriteLine(colName + " - " + row[colName]);
                    res.SetData(row[colName]?.ToString()??"", i, colName);
                }
            }
            return res;
        }

        public void ChangeMode(bool useThresholds, bool useCachTable)
        {
            if (_engineWrapper != null)
            {
                _engineWrapper.FloatThreshold = useThresholds;
                _engineWrapper.UseCacheTable = useCachTable;
            }
        }
        #endregion
    }
}
