using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using JWH.DATA;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;

namespace JWH.MONGODB
{
    public class FDCMongoDB
    {

        public static string ConnectionString { get; set; } = "mongodb://192.168.8.181:27001";

        public static string DatabaseName { get; set; } = "fdc";

        public static List<BsonDocument> GetListCollection()
        {
            MongoClient client = new MongoClient(ConnectionString);
            IMongoDatabase database = client.GetDatabase(DatabaseName);
            List<BsonDocument> item = database.ListCollectionsAsync().Result.ToListAsync<BsonDocument>().Result;

            return item;
        }

        public static async void GetCollectionColumns(string collectionName)
        {
            MongoClient client = new MongoClient(ConnectionString);
            IMongoDatabase database = client.GetDatabase(DatabaseName);
            var collection = database.GetCollection<BsonDocument>(collectionName);

            var pipeline = new[]
{
            new BsonDocument("$project", new BsonDocument("fields", new BsonDocument("$objectToArray", "$$ROOT"))),
            new BsonDocument("$unwind", "$fields"),
            new BsonDocument("$group", new BsonDocument("_id", BsonNull.Value).Add("uniqueFields", new BsonDocument("$addToSet", "$fields.k")))
        };

            var result = await collection.Aggregate<BsonDocument>(pipeline).FirstOrDefaultAsync();

            if (result != null && result.Contains("uniqueFields"))
            {
                var fields = result["uniqueFields"].AsBsonArray.Select(f => f.AsString);
                Console.WriteLine("컬렉션의 필드 목록:");
                foreach (var field in fields)
                {
                    Console.WriteLine(field);
                }
            }
        }

        public static List<TraceCollection> GetCollectionData(string collectionName, DateTime dtStart, DateTime dtEnd, TraceCollection condition = null)
        {
            try
            {
                MongoClient client = new MongoClient(ConnectionString);
                IMongoDatabase database = client.GetDatabase(DatabaseName);
                IMongoCollection<TraceCollection> collection = database.GetCollection<TraceCollection>(collectionName);

                // # ALL Data
                //var lst = collection.Find(_ => true).ToList();
                // # Use BsonDocument
                //var filter = new BsonDocument("LotID", "13089570006B");
                // # Use Builders.Filter
                //var filterBuilder = Builders<TraceCollection>.Filter;
                //var filter = filterBuilder.Eq(x => x.LotID, "13109360026B");

                FilterDefinitionBuilder<TraceCollection> filterBuilder = Builders<TraceCollection>.Filter;
                FilterDefinition<TraceCollection> filter = filterBuilder.Gte(x => x.EVENTTIME, dtStart) & filterBuilder.Lt(x => x.EVENTTIME, dtEnd);
                if (condition != null)
                {
                    string[] SkipPropertys = new string[] { "_id", "EVENTTIME" };
                    foreach (PropertyInfo property in condition.GetType().GetProperties())
                    {
                        object value = property.GetValue(condition);
                        if (value != null)
                        {
                            if (property.Name.Equals("LotID")) filter &= filterBuilder.Eq(x => x.LotID, value);
                            continue;
                        }
                    }
                }
                List<TraceCollection> document = collection.Find(filter).ToList();

                return document;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static bool GetCollectionSize_Flag = false;

        public static async void GetCollectionSize(string filename, Action<string> complete, params object[] controls)
        {
            GetCollectionSize_Flag = true;
            StreamWriter writer = null;
            BsonDocument document = null;
            try
            {
                ProgressBar progressBar = null;
                Control textBox = null;
                foreach(object ctrl in controls)
                {
                    if (ctrl.GetType() == typeof(ProgressBar)) progressBar = (ProgressBar)ctrl;
                    if (ctrl.GetType() == typeof(Label)) textBox = (Label)ctrl;
                    if (ctrl.GetType() == typeof(TextBox)) textBox = (TextBox)ctrl;
                }

                MongoClient client = new MongoClient(ConnectionString);
                IMongoDatabase database = client.GetDatabase(DatabaseName);
                List<BsonDocument> collections = database.ListCollectionsAsync().Result.ToListAsync<BsonDocument>().Result;

                if (progressBar != null)
                {
                    progressBar.Maximum = collections.Count;
                    progressBar.Minimum = 0;
                    progressBar.Value = 0;
                }

                string[] elementNames = new string[] { "size", "count", "avgObjSize", "storageSize", "freeStorageSize", "totalIndexSize", "totalSize" };
                StringBuilder sb = new StringBuilder();
                sb.Append($"EQ, SVID, name, ");
                foreach (string elementName in elementNames) sb.Append($"{elementName}, ");

                writer = new StreamWriter(filename);
                writer.WriteLine(sb.ToString());
                for (int i = 0; i < collections.Count; i++) 
                {
                    BsonDocument collection = collections[i];
                    string collectionName = collection.GetElement("name").Value.ToString();
                    var command = new JsonCommand<BsonDocument>("{collstats:\"" + collectionName + "\"}");
                    document = await database.RunCommandAsync(command);

                    string[] elementValues = new string[] { "", "", "", "", "", "", "" };
                    BsonElement[] elements = document.ToArray();
                    foreach(BsonElement element in elements)
                    {
                        for (int j = 0; j < elementNames.Length; j++)
                        {
                            if (element.Name == elementNames[j])
                            {
                                elementValues[j] = element.Value.ToString();
                                break;
                            }
                        }
                    }

                    sb.Clear();
                    string[] splitName = collectionName.Split('.');
                    if (splitName.Length == 2) sb.Append($"{splitName[0]}, {splitName[1]}, {collectionName}, ");
                    else sb.Append($", , {collectionName},");
                    foreach (string value in elementValues) sb.Append($"{value}, ");
                    writer.WriteLine(sb.ToString());

                    if (progressBar != null) progressBar.Value = i;
                    if (textBox != null) textBox.Text = $"{i.ToString("#,##0")} / {collections.Count.ToString("#,##0")}"; ;

                    if (!GetCollectionSize_Flag) break;
                }
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
                filename = string.Empty;
            }
            finally
            {
                FDCMongoDB.GetCollectionSize_Flag = false;
                if (writer != null) writer.Close();
                complete(filename);
            }
        }

        public class TraceCollection : DataTableBase
        {

            public ObjectId _id { get; set; }

            [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
            public DateTime EVENTTIME { get; set; }

            public string ProcessID { get; set; }

            public string UnitState { get; set; }


            public string VIDName { get; set; }

            public object Value { get; set; }

            public string Sign { get; set; }

            public List<object> LotList { get; set; }

            public string LotID { get; set; }

            public string ProductID { get; set; }

            public string Recipe { get; set; }

            public object UnitNO { get; set; }

            public string VORNR { get; set; }

            public string MaterialID { get; set; }

            public string CarrierId { get; set; }

            public string PanelId { get; set; }

            public string Position { get; set; }

            public string MarkingId { get; set; }

            public string Step { get; set; }

            public double LowerSV { get; set; }

            public double UpperSV { get; set; }

            public string MongGoUnitName { get; set; }

        }

    }

}
