using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Xml.Serialization;

namespace ProductDashboardMVC.Controllers
{
    public class ProductController : Controller
    {
        #region privateData
        static List<Order> orders = new List<Order>();
        static List<SalesStatus> sales = new List<SalesStatus>();
        string _ordersdata = string.Empty;
        string _salesdata = string.Empty;
        string _productsdata = string.Empty;

        int selectedMonth = default(int);
        string selectedProduct = string.Empty;
        static ModelData model;

        public ProductController()
        {

            this._ordersdata = AppDomain.CurrentDomain.BaseDirectory+ "//App_Data//ordersdata.xml";
            this._salesdata = AppDomain.CurrentDomain.BaseDirectory+ "//App_Data//salesdata.xml";

            model = new ModelData();
            if (orders.Count > 0 && sales.Count > 0)
            {

            }
            else
            {
                if (System.IO.File.Exists(_ordersdata) && System.IO.File.Exists(_salesdata))
                {

                    orders = this.GetOrdersData(_ordersdata);
                    sales = this.GetSalesData(_salesdata);
                }
                else
                {
                    orders = model.GetOrders();
                    sales = model.GetSalesStatus(orders);
                    this.SaveOrdersData(_ordersdata, orders);
                    this.SaveSalesData(_salesdata, sales);
                }
            }

            
        }
        #endregion
        // GET: Product
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Product()
        {

            return View();
        }
        /// <summary>
        /// Gets product wise revenue
        /// </summary>
        /// <param name="SelMonth"></param>
        /// <param name="SelProduct"></param>
        /// <returns></returns>
        public JsonResult GetProductsRevenue(int SelMonth, string SelProduct)
        {
            this.SelectedMonth = SelMonth;
            this.SelectedProduct = SelProduct;

            var prod = from order in orders
                       where order.Date.Month == SelMonth && order.Product == SelProduct
                       group order by order.Date.Day into grpOrder
                       select new SalesUnits
                       {
                           Day = grpOrder.First().Date.Day.ToString(),
                           Amount = Math.Round(grpOrder.Sum(x => x.Amount * x.Units) / 100),
                           Units = grpOrder.Sum(x => x.Units),
                           Company = grpOrder.First().Company,
                           Product = grpOrder.First().Product
                       };

            return Json(prod.ToList(), JsonRequestBehavior.AllowGet);


        }
        /// <summary>
        /// Gets the products
        /// </summary>
        /// <returns></returns>
        public JsonResult GetProducts()
        {
            return Json(model.GetProduct(), JsonRequestBehavior.AllowGet);
        }
        /// <summary>
        /// Category wise revenue
        /// </summary>
        /// <param name="SelMonth"></param>
        /// <param name="SelProduct"></param>
        /// <returns></returns>
        public JsonResult GetCategoryRevenue(int SelMonth, string SelProduct)
        {
            this.SelectedMonth = SelMonth;
            var categoryrev = from order in orders
                              where order.Date.Month == SelectedMonth
                              group order by order.Company into grpOrder
                              select new ProductRevenue()
                              {
                                  Company = grpOrder.First().Company,
                                  Amount = grpOrder.Sum(x => x.Amount * x.Units),
                                  Units = grpOrder.Sum(x => x.Units),
                                  Product = grpOrder.First().Product
                              };

            return Json(categoryrev.ToList(), JsonRequestBehavior.AllowGet);

        }

        public IEnumerable NewCustomerAdded
        {
            get
            {
                var cust = (from order in orders
                            where order.NewCustomer && order.Date.Month == SelectedMonth
                            orderby order.Date
                            group order by order.Product into grpOrders
                            select new KeyValuePair<string, Double>(grpOrders.First().Product, grpOrders.Count())).ToList();

                return cust;
            }
        }

        public IEnumerable ExistingCustomers
        {
            get
            {
                var cust = (from order in orders
                            where !order.NewCustomer && order.Date.Month == SelectedMonth
                            orderby order.Date
                            group order by order.Product into grpOrders
                            select new KeyValuePair<string, Double>(grpOrders.First().Product, grpOrders.Count())).ToList();

                return cust;
            }
        }
        /// <summary>
        /// Get ratio of old Vs new customer
        /// </summary>
        /// <param name="SelMonth"></param>
        /// <returns></returns>
        public JsonResult GetCustomerRatio(int SelMonth)
        {

            List<Customers> custratio = new List<Customers>();
            this.SelectedMonth = SelMonth;
            foreach (KeyValuePair<string, Double> cust in NewCustomerAdded)
            {
                foreach (KeyValuePair<string, Double> oldcust in ExistingCustomers)
                {
                    if (oldcust.Key == cust.Key)
                    {
                        Customers c = new Customers();
                        c.Product = cust.Key;
                        c.NewCustomer = cust.Value;
                        c.OldCustomer = oldcust.Value;
                        custratio.Add(c);
                        break;
                    }
                }

            }

            return Json(custratio, JsonRequestBehavior.AllowGet);

        }

        private double SelectedProductSales
        {
            get
            {
                 var prodsale = (from order in orders
                                where order.Product == SelectedProduct && order.Date.Month == SelectedMonth
                                select order.Amount * order.Units).Sum();

                return prodsale;
            }
            
        }
        /// <summary>
        /// Gets selected product revenue and total revenue
        /// </summary>
        /// <param name="SelMonth"></param>
        /// <param name="SelProduct"></param>
        /// <returns></returns>
        public JsonResult GetSelectedProductSale(int SelMonth, string SelProduct)
        {
            this.SelectedMonth = SelMonth;
            this.SelectedProduct = SelProduct;
            double[] revenue = new double[2] { SelectedProductSales ,TotalSales};

            return Json(revenue, JsonRequestBehavior.AllowGet);
        }
        /// <summary>
        /// Gets ratio of different order status
        /// </summary>
        /// <param name="SelMonth"></param>
        /// <param name="SelProduct"></param>
        /// <returns></returns>
        public JsonResult GetOrderStatusRatio(int SelMonth, string SelProduct)
        {
            this.SelectedMonth = SelMonth;
            this.SelectedProduct = SelProduct;
            var ordratio = (from sale in sales
                            where sale.Product == SelectedProduct
                            && sale.Date.Month == SelectedMonth
                            group sale by sale.Date.Month into grpSales
                            select new
                            {
                                CompletedOrders = grpSales.Sum(x => x.Completed),
                                InvalidOrders = grpSales.Sum(x => x.InvalidOrders),
                                InOrder = grpSales.Sum(x => x.InOrder),
                                TotalReturns = grpSales.Sum(x => x.Returns)

                            }).FirstOrDefault();

            List<KeyValuePair<string, double>> orderratio = new List<KeyValuePair<string, double>>();
            if (!ordratio.Equals(null))
            {
                orderratio.Add(new KeyValuePair<string, double>("Completed", ordratio.CompletedOrders));
                orderratio.Add(new KeyValuePair<string, double>("Invalid", ordratio.InvalidOrders));
                orderratio.Add(new KeyValuePair<string, double>("InOrder", ordratio.InOrder));
                orderratio.Add(new KeyValuePair<string, double>("Total Returns", ordratio.TotalReturns));
            }
            return Json(orderratio, JsonRequestBehavior.AllowGet);

        }
        /// <summary>
        /// Gets percentage of products sale against total sales
        /// </summary>
        /// <param name="SelMonth"></param>
        /// <returns></returns>
        public JsonResult GetSalesRatio(int SelMonth)
        {
            this.SelectedMonth = SelMonth;
            double totalsale = TotalSales;
            var saleratio = (from order in orders
                             where order.Date.Month == SelectedMonth
                             group order by order.Product into grpOrder
                             select new
                             {
                                 Product = grpOrder.First().Product,
                                 SalesRatio =Math.Round( (grpOrder.Sum(x => x.Amount * x.Units) / TotalSales) * 100),
                                 Units = grpOrder.Sum(x => x.Units)
                             }).ToList();

            return Json(saleratio, JsonRequestBehavior.AllowGet);


        }

        double selectedProductSales = default(double);
        public double SalesPercentage
        {
            get
            {
                return (SelectedProductSales / TotalSales) * 100;
            }
        }

        public double TotalSales
        {
            get
            {
                var totalsales = (from order in orders
                                  where order.Date.Month == SelectedMonth
                                  select order.Amount * order.Units).Sum();
                return totalsales;
            }
        }

        public int SelectedMonth
        {
            get { return selectedMonth; }
            set { selectedMonth = value; }
        }

        public string SelectedProduct
        {
            get { return selectedProduct; }
            set { selectedProduct = value; }
        }

        XmlSerializer ordersSerializer = new XmlSerializer(typeof(List<Order>));

        /// <summary>
        /// Save Order to xml data file
        /// </summary>
        /// <param name="fileName">File to which data is to be saved</param>
        /// <param name="orderList">List of order items</param>
        public void SaveOrdersData(string fileName, List<Order> orderList)
        {
            using (FileStream fs = System.IO.File.OpenWrite(fileName))
            {
                ordersSerializer.Serialize(fs, orderList);
            }
        }

        /// <summary>
        /// Get order data from xml file.
        /// </summary>
        /// <param name="fileName">File from which data is to be retreived</param>
        /// <returns>List of Order's</returns>
        public List<Order> GetOrdersData(string fileName)
        {
            using (FileStream fs = System.IO.File.OpenRead(fileName))
            {
                List<Order> list = (List<Order>)ordersSerializer.Deserialize(fs);
                return list;
            }
        }

        XmlSerializer salesStatusSerializer = new XmlSerializer(typeof(List<SalesStatus>));

        /// <summary>
        /// Save Sales data to xml file.
        /// </summary>
        /// <param name="fileName">File to which data is to be saved</param>
        /// <param name="salesList">List of sales status</param>
        public void SaveSalesData(string fileName, List<SalesStatus> salesList)
        {
            using (FileStream fs = System.IO.File.OpenWrite(fileName))
            {
                salesStatusSerializer.Serialize(fs, salesList);
            }
        }

        /// <summary>
        /// Get sales data from xml file.
        /// </summary>
        /// <param name="fileName">File from which data is to be retrieved</param>
        /// <returns>List of sales status</returns>
        public List<SalesStatus> GetSalesData(string fileName)
        {
            using (FileStream fs = System.IO.File.OpenRead(fileName))
            {
                List<SalesStatus> list = (List<SalesStatus>)salesStatusSerializer.Deserialize(fs);
                return list;
            }
        }

    }
}