using ClosedXML.Excel;
using Dapper;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.IO;
using System.Text.Json;

namespace FormCompareTools
{
    internal class Program
    {
        static string GetParametersFile(string[] args)
        {
            if (args.Length == 0)
            {
                return null;
            }
            var inputParametersJson = args[0];
            if (File.Exists(inputParametersJson))
            {
                return inputParametersJson;
            }

            string appDirectory = AppDomain.CurrentDomain.BaseDirectory;
            if (File.Exists(Path.Combine(appDirectory, inputParametersJson)))
            {
                return inputParametersJson;
            }
            return null;
        }

        static string GetFormParametersFile(string[] args)
        {
            if (args.Length < 2)
            {
                return null;
            }

            var inputParametersJson = args[1];
            if (File.Exists(inputParametersJson))
            {
                return inputParametersJson;
            }

            string appDirectory = AppDomain.CurrentDomain.BaseDirectory;
            if (File.Exists(Path.Combine(appDirectory, inputParametersJson)))
            {
                return inputParametersJson;
            }
            return null;
        }

        static void Main(string[] args){
            var inputParametersJson = GetParametersFile(args);
            var inputFormParametersJson = GetFormParametersFile(args);

            if (string.IsNullOrWhiteSpace(inputParametersJson) || string.IsNullOrWhiteSpace(inputFormParametersJson))
            {
                Console.WriteLine("Use FormCompareTool test_parameters.json form_parameters.json");
                return;
            }

            InputParameters inputParameters;
            using (var fs = File.OpenRead(inputParametersJson))
            {
                inputParameters = JsonSerializer.Deserialize<InputParameters>(fs);
            }

            FormParameters formParameters;
            using (var fs = File.OpenRead(inputFormParametersJson))
            {
                formParameters = JsonSerializer.Deserialize<FormParameters>(fs);
            }

            var sheetName = $"{inputParameters.FormName}_{inputParameters.TestName}";

            var wb = new XLWorkbook(inputParameters.ExcelTemplate);

            if (wb.TryGetWorksheet(sheetName, out var worksheet))
            {
                var lines = formParameters.Columns;
                var databaseFields = new List<string>();
                for (int i = inputParameters.FirstRow; i <= inputParameters.LastRow; i++)
                {
                    var lineCell = $"{inputParameters.LinesColumn}{i}";
                    string lineNumber = GetCellValue(worksheet, lineCell);

                    if (lines.TryGetValue(lineNumber, out var lineDatabaseField))
                    {
                        databaseFields.Add(lineDatabaseField);
                    }
                }

                (var dbResult, var dt) = ReadFromDatabase(inputParameters.PrimarySsn, inputParameters.FormName, databaseFields, formParameters);
                if (dbResult)
                {
                    for (int i = inputParameters.FirstRow; i <= inputParameters.LastRow; i++)
                    {
                        var databaseValueCell = $"{inputParameters.DatabaseColumn}{i}";
                        var lineCell = $"{inputParameters.LinesColumn}{i}";
                        var lineNumber = GetCellValue(worksheet, lineCell);

                        if (lines.TryGetValue(lineNumber, out var lineDatabaseField))
                        {
                            var rawValue = dt.Rows[0][lineDatabaseField];
                            if (int.TryParse(rawValue.ToString(), out var intValue))
                            {
                                worksheet.Cell(databaseValueCell).Value = intValue;
                            }
                            else if (decimal.TryParse(rawValue.ToString(), out var decimalValue))
                            {
                                worksheet.Cell(databaseValueCell).Value = decimalValue;
                            }
                            else
                            {
                                worksheet.Cell(databaseValueCell).Value = rawValue.ToString();
                            }
                        }
                    }

                    worksheet.Cell(inputParameters.PrimarySsnCell).Value = inputParameters.PrimarySsn;
                    var uniqueKey = DateTime.Now.ToString("MMddhhmm");
                    var excelOutputFileName = string.Format(inputParameters.ExcelOutput, uniqueKey);
                    wb.SaveAs(excelOutputFileName);
                    Console.WriteLine($"Saved to {excelOutputFileName}");
                }
            }
            if (Environment.UserInteractive)
            {
                Console.WriteLine($"Press any key to exit...");
                Console.ReadLine();
            }
        }

        private static string GetCellValue(IXLWorksheet worksheet, string lineCell)
        {
            var lineNumber = string.Empty;
            if (worksheet.Cell(lineCell).Value.IsText)
            {
                lineNumber = worksheet.Cell(lineCell).Value.GetText();
            }
            else if (worksheet.Cell(lineCell).Value.IsNumber)
            {
                lineNumber = $"{worksheet.Cell(lineCell).Value.GetNumber()}";
            }

            return $"line_{lineNumber}";
        }

        static (bool result, DataTable table) ReadFromDatabase(string primaryssn, string formName, List<string> fieldNames, FormParameters formParameters)
        {
            var database = ConfigurationManager.AppSettings["database"];
            var connectionString = ConfigurationManager.ConnectionStrings[database].ConnectionString;

            var sql = $"SELECT {string.Join(",", fieldNames)} FROM {formParameters.MainTableName} WHERE primaryssn='{primaryssn}' LIMIT 1";

            using (var conn = new MySql.Data.MySqlClient.MySqlConnection(connectionString))
            {
                var reader = conn.ExecuteReader(sql);
                var dt = new DataTable();
                foreach(var field in fieldNames)
                {
                    dt.Columns.Add(field, typeof(string));
                }
                dt.Load(reader);
                return (dt.Rows.Count > 0, dt);
            }
        }
    }
}