using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Электронная_Фармация.Classes;
using System.IO;
using System.Data.SQLite;

namespace Электронная_Фармация.Forms
{
    public partial class FCheckDatabaseIntegrary : Form
    {

        public FCheckDatabaseIntegrary()
        {
            InitializeComponent();
        }

        string currentDirectoryPath = (System.IO.Directory.GetCurrentDirectory());
        
        private void FCheckDatabaseIntegrary_Load(object sender, EventArgs e)
        {
            UiThemeHelper.ApplyToControlTree(this);
            checkDatabaseWasExists();
            checkTablesExists();
            this.Close();
        }


        void checkDatabaseWasExists()
        {
            var dbPath = AppConfig.SqliteDbPath;
            var dir = Path.GetDirectoryName(dbPath);
            if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            if (!File.Exists(dbPath))
            {
                SQLiteConnection.CreateFile(dbPath);
            }
        }

        void checkTablesExists()
        {
            string connectionStringToLocalDB = AppConfig.SqliteConnectionString;
            //MessageBox.Show(connectionStringToLocalDB);
            using (SQLiteConnection conForCheckTables = new SQLiteConnection(connectionStringToLocalDB))
            {
                try
                {
                    conForCheckTables.Open();

                    string strCheckExistsSuppliers = @"
    create table if not exists [Suppliers] (
    [idSuppliers] integer primary key AUTOINCREMENT not null,
    [codeSuppliers] integer not null,
    [SuppliersName] nvarchar(128) not null,
    [SuppliersTelephone] nvarchar(64),
    [SuppliersEmail] nvarchar(128),
    [SuppliersAddress] nvarchar(256),
    [MinimalSumOfOrder] real,
    [OrdersPath] text
    )
    ";

                    string strCheckExistsConsignees = @"
    create table if not exists [Consignees] (
    [idConsignees] integer primary key AUTOINCREMENT not null,
    [codeConsignees] integer not null,
    [ConsigneesName] nvarchar(128) not null,
    [ConsigneesAddress] nvarchar(256) not null,
    [ConsigneesUseAsDefault] int(1) not null,
    [LocationId] nvarchar(64)
    )
";

                    string strCheckExistsInvoices = @"
    create table if not exists [Invoice] (
    [idInvoice] integer primary key AUTOINCREMENT not null,
    [InvoiceNumber] nvarchar(128) not null,
    [InvoiceDate] integer not null,
    [CodeSupplier] integer not null,
    [CodeConsignees] integer not null,
    [SumWithoutNDS] real,
    [SumWithNDS] real,
    [SumNDS] real
    )
";
                    string strCheckExistsInvoiceItem = @"
    create table if not exists [InvoiceItem] (
    [idInvoiceItem] integer primary key AUTOINCREMENT not null,
    [idGood] integer,
    [GoodCode] integer not null,
    [Good] nvarchar(256) not null,
    [ProducerName] nvarchar(256),
    [CountryName] nvarchar(256),
    [idInvoice] interger not null,
    [GoodsGount] integer not null,
    [PriceSupplierWithoutNDS] real,
    [PriceSupplierWithNDS] real,
    [PriceProducerWithoutNDS] real,
    [PriceProducerWithNDS] real,
    [NDS] integer,
    [JNVLS] int(1),
    [PriceReestr] real,
    [SumWithoutNDS] real,
    [SumWithNDS] real,
    [SumNDS] real,
    [Serial] nvarchar(24),
    [BestBefore] text,
    [Sertificate] nvarchar(128),
    [Marked] int(1) not null,
    [GTIN] nvarchar(14)
    )
";

                    string strCheckExistsTableGoods = @"
    create table if not exists [Goods] (
    [idGood] integer primary key AUTOINCREMENT not null,
    [GoodCode] integer not null,
    [GoodName] nvarchar(256) not null,
    [idProducer] integer not null,
    [JNVLS] int(1),
    [CurrentReestrPrice] real,
    [idGoodsGroup] integer,
    [idGoodsShortNameForSearch] integer
    )
";

                    string strCheckExistsTableProducers = @"
    create table if not exists [Producers] (
    [idProcuder] integer primary key AUTOINCREMENT not null,
    [ProducerCode] integer not null,
    [ProducerName] nvarchar(256) not null,
    [idCountry] integer not null
    )
";

                    string strCheckExistsTableCountries = @"
    create table if not exists [Countries] (
    [idCountry] integer primary key AUTOINCREMENT not null,
    [CountryCode] integer not null,
    [CountryName] nvarchar(256) not null
    )
";

                    string strCheckExistsTableReestrPriceHistory = @"
    create table if not exists [ReestrPriceHistoryForGoods] (
    [idReestrPriceHistory] integer primary key AUTOINCREMENT not null,
    [GoodCode] integer not null,
    [ReestrPriceDateCreate] text not null,
    [ReestrPrice] real not null,
    [ReestrPricePeriodFrom] text,
    [ReestrPricePeriodTo] text
    )
";

                    string strCheckExistsTablePriceHistory = @"
    create table if not exists [SuppliersPriceHistoryForGoods] (
    [idSuppliersPriceHistoryForGoods] integer primary key AUTOINCREMENT not null,
    [GoodsCode] integer not null,
    [PriceDate] text not null,
    [MinPriceForGood] real,
    [AvgPriceForGood] real,
    [MaxPriceForGood] real
    )
";

                    string strCheckExistsTableGoodsGroup = @"
    create table if not exists [GoodsGroup] (
    [idGoodsGroup] integer primary key AUTOINCREMENT not null,
    [GoodsGroupCode] integer not null,
    [GoodsGroupName] nvarchar(256) not null
    )
";

                    string strCheckExistsTableGoodsShortNameForSearch = @"
    create table if not exists [GoodsShortNameForSearch] (
    [idGoodsShortNameForSearch] integer primary key AUTOINCREMENT not null,
    [GoodsShortNameForSearchCode] integer not null,
    [GoodsShortNameForSearchCodeName] nvarchar(255) not null
    )
";
                    string strCheckExistsTablePriceListFromSuppliers = @"
    create table if not exists [PriceListFromSuppliers] (
    [idPriceListSuppliers] integer primary key AUTOINCREMENT not null,
    [ConsigneesCode] integer not null,
    [CodeSuppliers] integer not null,
    [PriceListDate] datetime
    )
";

                    string strCheckExistsTablePriceList = @"
create table if not exists [PriceList] (
[guid_es] nvarchar(36) not null,
[es_code] integer not null,
[supplier_id] nvarchar(36) not null,
[DrugName] nvarchar(256) not null COLLATE NOCASE,
[SupplierName] nvarchar(256) not null,
[Price] nvarchar(32),
[Quantity] integer,
[ExpiryPeriod] nvarchar(64),
[Description] text,
[Zakaz] nvarchar(64),
[SummaZakaza] nvarchar(64),
[id_PriceList_Item] integer primary key AUTOINCREMENT not null,
[supplier_price_id] nvarchar(36)
)
";

                    #region Старая таблица Прайс-листа
                    //                    string strCheckExistsTablePriceList = @"
                    //    create table if not exists [PriceList] (
                    //    [idPriceListSupplier] integer not null,
                    //    [ConsigneesCode] integer not null,
                    //    [idPriceList] integer primary key AUTOINCREMENT not null,
                    //    [GoodCode] integer,
                    //    [GoodName] nvarchar(256) not null COLLATE NOCASE,
                    //    [ProducerName] nvarchar(256),
                    //    [SupplierName] nvarchar(256) not null,
                    //    [BestBefore] text,
                    //    [JNVLS] int(1),
                    //    [PriceReestr] real,
                    //    [AvaibleCount] integer not null,
                    //    [PriceSupplierWithNDS] real not null,
                    //    [CountIWantBuy] integer,
                    //    [SumIWantBuy] real,
                    //    [CountryName] nvarchar(256),
                    //    [NDS] integer,
                    //    [PriceProducer] real,
                    //    [Marked] int(1)
                    //    )
                    //";
                    #endregion

                    string strCheckExistsTableOrders = @"
create table if not exists [Orders] (
[Id_Order] integer primary key AUTOINCREMENT not null,
[OrderNumber] nvarchar(36) not null,
[OrderDate] nvarchar(10) not null,
[Id_Supplier] nvarchar(36) not null,
[SupplierName] nvarchar(256) not null,
[OrderedCountItems] integer,
[SummaZakaza] nvarchar(32),
[OrderState] nvarchar(32),
[Comment] nvarchar(1024),
[ConsigneeName] nvarchar(128),
[RemoteOrderId] nvarchar(36)
)
";

                    string strCheckExistsTableOrderItems = @"
create table if not exists [OrderItems] (
[Id_Order_Item] integer primary key AUTOINCREMENT not null,
[Id_Order] integer not null,
[guid_es] nvarchar(36),
[es_code] integer,
[DrugName] nvarchar(256) not null COLLATE NOCASE,
[Price] nvarchar(32),
[Zakaz] integer,
[SummaZakaza] nvarchar(32),
[ExpiryPeriod] nvarchar(64),
[RefuseItemsCount] integer,
[supplier_price_id] nvarchar(36)
)
";


                    #region старые таблицы Orders и OrderItem

//                    string strCheckExistsTableOrders = @"
//    create table if not exists [Orders] (
//    [idOrder] integer primary key AUTOINCREMENT not null,
//    [OrderNumber] nvarchar(10) not null,
//    [OrderDate] integer not null,
//    [codeSuppliers] integer not null,
//    [codeConsignees] integer not null,
//    [OrderedItemsCount] integer not null,
//    [OrderSum] real not null,
//    [RefuseItemsCount] integer,
//    [RefuseSum] real,
//    [Comment] text,
//    [OrderState] nvarchar(4)
//    )
//";

//                    string strCheckExistsTableOrderItems = @"
//    create table if not exists [OrderItems] (
//    [idOrderItem] integer primary key AUTOINCREMENT not null,
//    [idOrder] integer not null,
//    [GoodCode] integer,
//    [GoodName] nvarchar(256) not null,
//    [OrderedCountItems] integer not null,
//    [SupplierPrice] real not null,
//    [SumOrderedItems] real not null,
//    [RefuseItemsCount] integer,
//    [BestBefore] text,
//    [ProducerName] nvarchar(256)
//    )
//";
                    #endregion

                    string strCheckExistsTableTempOrderItems = @"
    create table if not exists [TempOrderItems] (
    [ConsigneeName] nvarchar(128) not null,
    [guid_es] nvarchar(36) not null,
[es_code] integer not null,
[supplier_id] nvarchar(36) not null,
[DrugName] nvarchar(256) not null COLLATE NOCASE,
[SupplierName] nvarchar(256) not null,
[Price] nvarchar(32),
[Quantity] integer,
[ExpiryPeriod] nvarchar(64),
[Description] text,
[Zakaz] real,
[SummaZakaza] nvarchar(64),
    [id_PriceList_Item] integer not null,
    [supplier_price_id] nvarchar(36),
    primary key ([ConsigneeName], [id_PriceList_Item])
    )
";

                    #region Старая временная таблица OrderItem
//                    string strCheckExistsTableTempOrderItems = @"
//    create table if not exists [TempOrderItems] (
//    [GoodCode] integer,
//    [GoodName] nvarchar(256) not null collate nocase,
//    [SupplierName] nvarchar(128) not null,
//    [ConsigneesName] nvarchar(128) not null,
//    [OrderedCountItems] integer not null,
//    [SumOrderedItems] real not null,
//    [SupplierPrice] real not null,
//    [BestBefore] text
//    )
//";
                    #endregion


                    SQLiteCommand cmdCreateNotExistingsTables = conForCheckTables.CreateCommand();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsSuppliers;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsConsignees;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsInvoices;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsInvoiceItem;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTableGoods;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTableGoods;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTableProducers;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTableCountries;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTableReestrPriceHistory;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTablePriceHistory;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTableGoodsGroup;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTableGoodsShortNameForSearch;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTablePriceListFromSuppliers;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTablePriceList;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTableOrders;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTableOrderItems;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    cmdCreateNotExistingsTables.CommandText = strCheckExistsTableTempOrderItems;
                    cmdCreateNotExistingsTables.ExecuteNonQuery();

                    // Миграция TempOrderItems под раздельную корзину по аптекам.
                    // Проверяем наличие ConsigneeName и то, что id_PriceList_Item не является одинарным PK.
                    bool hasConsigneeName = false;
                    bool idPriceListItemIsSinglePk = false;
                    using (var infoCmd = new SQLiteCommand("PRAGMA table_info([TempOrderItems]);", conForCheckTables))
                    using (var infoReader = infoCmd.ExecuteReader())
                    {
                        while (infoReader.Read())
                        {
                            var colName = infoReader["name"]?.ToString();
                            var pk = 0;
                            try { pk = Convert.ToInt32(infoReader["pk"]); } catch { pk = 0; }

                            if (string.Equals(colName, "ConsigneeName", StringComparison.OrdinalIgnoreCase))
                            {
                                hasConsigneeName = true;
                            }

                            if (string.Equals(colName, "id_PriceList_Item", StringComparison.OrdinalIgnoreCase) && pk == 1)
                            {
                                idPriceListItemIsSinglePk = true;
                            }
                        }
                    }

                    if (!hasConsigneeName || idPriceListItemIsSinglePk)
                    {
                        string defaultConsignee;
                        using (var defCmd = new SQLiteCommand(
                            @"SELECT ifnull((SELECT ConsigneesName
                                               FROM Consignees
                                               WHERE ConsigneesUseAsDefault = 1
                                               LIMIT 1), '')",
                            conForCheckTables))
                        {
                            defaultConsignee = defCmd.ExecuteScalar()?.ToString() ?? string.Empty;
                        }

                        using (var tx = conForCheckTables.BeginTransaction())
                        {
                            using (var cmd = new SQLiteCommand(conForCheckTables))
                            {
                                cmd.Transaction = tx;

                                cmd.CommandText = @"
CREATE TABLE IF NOT EXISTS [TempOrderItems_new] (
    [ConsigneeName] nvarchar(128) not null,
    [guid_es] nvarchar(36) not null,
    [es_code] integer not null,
    [supplier_id] nvarchar(36) not null,
    [DrugName] nvarchar(256) not null COLLATE NOCASE,
    [SupplierName] nvarchar(256) not null,
    [Price] nvarchar(32),
    [Quantity] integer,
    [ExpiryPeriod] nvarchar(64),
    [Description] text,
    [Zakaz] real,
    [SummaZakaza] nvarchar(64),
    [id_PriceList_Item] integer not null,
    [supplier_price_id] nvarchar(36),
    primary key ([ConsigneeName], [id_PriceList_Item])
);";
                                cmd.ExecuteNonQuery();

                                cmd.Parameters.Clear();
                                cmd.Parameters.AddWithValue("@defaultConsignee", defaultConsignee.Trim());
                                cmd.CommandText = @"
INSERT INTO [TempOrderItems_new] (
    [ConsigneeName],
    [guid_es],
    [es_code],
    [supplier_id],
    [DrugName],
    [SupplierName],
    [Price],
    [Quantity],
    [ExpiryPeriod],
    [Description],
    [Zakaz],
    [SummaZakaza],
    [id_PriceList_Item],
    [supplier_price_id]
)
SELECT
    @defaultConsignee,
    [guid_es],
    [es_code],
    [supplier_id],
    [DrugName],
    [SupplierName],
    [Price],
    [Quantity],
    [ExpiryPeriod],
    [Description],
    [Zakaz],
    [SummaZakaza],
    [id_PriceList_Item],
    [supplier_price_id]
FROM [TempOrderItems];";
                                cmd.ExecuteNonQuery();

                                cmd.Parameters.Clear();
                                cmd.CommandText = @"DROP TABLE [TempOrderItems];";
                                cmd.ExecuteNonQuery();

                                cmd.CommandText = @"ALTER TABLE [TempOrderItems_new] RENAME TO [TempOrderItems];";
                                cmd.ExecuteNonQuery();
                            }

                            tx.Commit();
                        }
                    }

                    // LocationId нужен для связи с BuyerLocation на сервере.
                    TryAddColumn(conForCheckTables, "Consignees", "LocationId", "nvarchar(64)");

                    // Удаляем старые тестовые грузополучатели — точки создаются в веб-кабинете.
                    using (var delTest = new SQLiteCommand(
                        @"DELETE FROM Consignees
                          WHERE ConsigneesName LIKE 'Тестовая аптека%'
                             OR ConsigneesAddress LIKE 'Тестовый адрес%';",
                        conForCheckTables))
                    {
                        delTest.ExecuteNonQuery();
                    }

                    TryAddColumn(conForCheckTables, "Orders", "ConsigneeName", "nvarchar(128)");
                    TryAddColumn(conForCheckTables, "Invoice", "SupplierName", "nvarchar(256)");
                    TryAddColumn(conForCheckTables, "Invoice", "ConsigneesName", "nvarchar(128)");
                    TryAddColumn(conForCheckTables, "Invoice", "InvoiceSum", "nvarchar(64)");
                    TryAddColumn(conForCheckTables, "Invoice", "RefuseSum", "nvarchar(64)");
                    TryAddColumn(conForCheckTables, "Invoice", "SourceOrderId", "integer");
                    TryAddColumn(conForCheckTables, "Invoice", "SourceOrderNumber", "nvarchar(36)");
                    TryAddColumn(conForCheckTables, "Invoice", "IsRequestedInvoice", "int(1)");
                    TryAddColumn(conForCheckTables, "Orders", "RemoteOrderId", "nvarchar(36)");
                    TryAddColumn(conForCheckTables, "PriceList", "TradeName", "nvarchar(256)");
                    TryAddColumn(conForCheckTables, "PriceList", "Dosage", "nvarchar(128)");
                    TryAddColumn(conForCheckTables, "PriceList", "MarkupPercent", "real");
                    TryAddColumn(conForCheckTables, "Consignees", "ClientMarkupPercent", "real");
                    ConsigneeHelper.MigrateGlobalLocationIdIfNeeded(conForCheckTables);
                }
                catch (Exception ex)
                {
                    try
                    {
                        var logDir = AppConfig.LogsDirectory;
                        Directory.CreateDirectory(logDir);
                        var logPath = Path.Combine(
                            logDir,
                            $"db-integrity-err-{DateTime.Now:yyyy-MM-dd}.log");

                        File.AppendAllText(
                            logPath,
                            $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} {ex}{Environment.NewLine}{Environment.NewLine}",
                            Encoding.UTF8);
                    }
                    catch
                    {
                        // Логирование не должно скрывать исходную ошибку.
                    }

                    UiDialogs.ShowError($"Возникла ошибка при проверке локальной базы на целостность.\n{ex}", "Ошибка целостности", this);
                }
                finally
                {
                    conForCheckTables.Close();
                }
            }
        }

        private static void TryAddColumn(SQLiteConnection connection, string tableName, string columnName, string columnType)
        {
            using (var infoCmd = new SQLiteCommand($"PRAGMA table_info([{tableName}])", connection))
            using (var reader = infoCmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    if (string.Equals(reader["name"].ToString(), columnName, StringComparison.OrdinalIgnoreCase))
                    {
                        return;
                    }
                }
            }

            using (var alterCmd = new SQLiteCommand($"ALTER TABLE [{tableName}] ADD COLUMN [{columnName}] {columnType}", connection))
            {
                alterCmd.ExecuteNonQuery();
            }
        }
    }
}
