using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace JtkPcClientWpf {
    public class OrderListItem : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged;

        Product product;
        public Product Product {
            get => product;
            private set { product = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Product")); }
        }

        int quantity;
        public int Quantity {
            get => quantity;
            set { quantity = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Quantity")); }
        }

        public OrderListItem(Product product, int quantity) {
            Product = product;
            Quantity = quantity;
        }

        public double TotalPrice {
            get => Product.Cost * Quantity;
        }

        public override bool Equals(object obj) {
            if (obj is OrderListItem item) {
                return Product == item.Product && Quantity == item.Quantity;
            } else {
                return false;
            }
        }
    }
    public class Product : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged;

        string name;
        public string Name {
            get => name;
            private set { name = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name")); }
        }

        double cost;
        public double Cost {
            get => cost;
            private set { cost = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Cost")); }
        }

        public Product(string name, double cost) {
            Name = name;
            Cost = cost;
        }

        public override bool Equals(object obj) {
            if (obj is Product prod) {
                return Name == prod.Name && Cost == prod.Cost;
            } else {
                return false;
            }
        }
    }
    public sealed class OrderManager : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged;
        private static readonly bool designMode = !(Application.Current is App);

        public void UpdateTotalCost() {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TotalCost"));
        }

        public readonly LoginManager LoginManager = Application.Current.Resources["loginManager"] as LoginManager;

        public double totalCost = designMode ? 2100 : 0;
        /// <summary>
        /// 선택된 상품의 총 가격입니다.
        /// </summary>
        public double TotalCost {
            get => orderList != null ? (from i in orderList select i.TotalPrice).Sum() : 0;
            private set { totalCost = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TotalCost")); }
        }

        public string memo = string.Empty;
        /// <summary>
        /// 주문 시, 요청 사항 입니다.
        /// </summary>
        public string Memo {
            get => memo;
            set { memo = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Memo")); }
        }

        public IEnumerable<string> categories = designMode ? new string[] { "인기상품", "이벤트", "커피류", "음료류", "과자류", "라면", "간식류", "냉동류"} : null;
        /// <summary>
        /// 카테고리 이름들입니다.
        /// </summary>
        public IEnumerable<string> Categories {
            get => categories;
            private set { categories = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Categories")); }
        }

        public IEnumerable<Product> currentCategoryProducts = designMode ? new Product[] {
                new Product("불닭볶음면", 2000),
                new Product("진짬뽕", 1500),
                new Product("ABC", 2000),
                new Product("DEF", 1500),
                new Product("GHI", 2000),
                new Product("JKL", 1500),
                new Product("MNO", 2000),
                new Product("PQRS", 1500),
                new Product("TUVW", 2000),
                new Product("XYZ", 1500)

        } : null;
        /// <summary>
        /// 현재 카테고리의 상품들입니다.
        /// </summary>
        public IEnumerable<Product> CurrentCategoryProducts {
            get => currentCategoryProducts;
            private set { currentCategoryProducts = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentCategoryProducts")); }
        }

        private IEnumerable<OrderListItem> orderList = designMode ? new OrderListItem[] {
                new OrderListItem(new Product("불닭볶음면", 2000), 10),
                new OrderListItem(new Product("진짬뽕", 1500), 2)
        } : null;
        /// <summary>
        /// 주문할 상품 목록입니다.
        /// </summary>
        public IEnumerable<OrderListItem> OrderList {
            get => orderList;
            set { orderList = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("OrderList")); }
        }

        /// <summary>
        /// 지불 방법입니다. cash, card, point
        /// </summary>
        public string PaymentMethod = "";

        readonly Dictionary<string, List<(string name, double price)>> orderMenu = new Dictionary<string, List<(string name, double price)>>();

        public void RefreshList() {
            var task = LoginManager.GetPostResponseAsync(new {
                work = "get_order_menu",
                pc_id = LoginManager.PcId,
                auth_key = LoginManager.AuthorizationKey
            });
            task.Wait();
            var result = task.Result["order_menu"].ToString();
            orderMenu.Clear();
            var cats = new List<string>();
            foreach (var cat in JObject.Parse(result)) {
                cats.Add(cat.Key);
                orderMenu[cat.Key] = new List<(string name, double price)>();
                foreach (var item in cat.Value) {
                    orderMenu[cat.Key].Add((item["name"].ToString(), item["price"].ToObject<double>()));
                }
            }
            Categories = cats.ToArray(); ;
            OrderList = new OrderListItem[0];
            Memo = "";
            PaymentMethod = "";
        }


        

        public void SelectCategory(string category) {
            var list = new List<Product>();
            foreach (var item in orderMenu[category]) {
                list.Add(new Product(item.name, item.price));
            }
            CurrentCategoryProducts = list;
        }

        public bool SubmitOrder(out string error) {
            if (OrderList.Count() == 0) {
                error = "주문할 상품을 추가하세요.";
                return false;
            }
            if (string.IsNullOrEmpty(PaymentMethod)) {
                error = "결제수단을 선택하세요.";
                return false;
            }
            var orderList = new List<(string name, int quantity)>();
            foreach (var item in OrderList) {
                orderList.Add((item.Product.Name, item.Quantity));
            }
            var task = LoginManager.GetPostResponseAsync(new {
                work = "submit_order",
                user_id = LoginManager.UserId,
                order_list = orderList,
                memo = Memo,
                payment_method = PaymentMethod,
                pc_id = LoginManager.PcId,
                total_price = TotalCost,
                auth_key = LoginManager.AuthorizationKey
            });
            task.Wait();
            var result = task.Result;
            if (result["result"].ToString() != "ok") {
                if (result["error"].ToString() == "cash_sparse") {
                    error = "잔액이 부족합니다.";
                    return false;
                } else {
                    error = "주문이 거절되었습니다.";
                    return false;
                }
            } else {
                error = null;
                return true;
            }
        }
    }
}
