using System;
using System.Globalization;
using System.Linq;
using Billing.Languages;
using Billing.Models;
using Billing.UI;
using Xamarin.Forms;

namespace Billing.Views
{
    public partial class AddBillPage : BillingPage
    {
        private static readonly BindableProperty AmountProperty = BindableProperty.Create(nameof(Amount), typeof(string), typeof(AddBillPage));
        private static readonly BindableProperty NameProperty = BindableProperty.Create(nameof(Name), typeof(string), typeof(AddBillPage));
        private static readonly BindableProperty CategoryNameProperty = BindableProperty.Create(nameof(CategoryName), typeof(string), typeof(AddBillPage));
        private static readonly BindableProperty WalletNameProperty = BindableProperty.Create(nameof(WalletName), typeof(string), typeof(AddBillPage));
        private static readonly BindableProperty StoreProperty = BindableProperty.Create(nameof(Store), typeof(string), typeof(AddBillPage));
        private static readonly BindableProperty CreatedDateProperty = BindableProperty.Create(nameof(CreatedDate), typeof(DateTime), typeof(AddBillPage));
        private static readonly BindableProperty CreatedTimeProperty = BindableProperty.Create(nameof(CreatedTime), typeof(TimeSpan), typeof(AddBillPage));
        private static readonly BindableProperty NoteProperty = BindableProperty.Create(nameof(Note), typeof(string), typeof(AddBillPage));

        public string Amount
        {
            get => (string)GetValue(AmountProperty);
            set => SetValue(AmountProperty, value);
        }
        public string Name
        {
            get => (string)GetValue(NameProperty);
            set => SetValue(NameProperty, value);
        }
        public string CategoryName => (string)GetValue(CategoryNameProperty);
        public string WalletName => (string)GetValue(WalletNameProperty);
        public string Store
        {
            get => (string)GetValue(StoreProperty);
            set => SetValue(StoreProperty, value);
        }
        public DateTime CreatedDate
        {
            get => (DateTime)GetValue(CreatedDateProperty);
            set => SetValue(CreatedDateProperty, value);
        }
        public TimeSpan CreatedTime
        {
            get => (TimeSpan)GetValue(CreatedTimeProperty);
            set => SetValue(CreatedTimeProperty, value);
        }
        public string Note
        {
            get => (string)GetValue(NoteProperty);
            set => SetValue(NoteProperty, value);
        }

        public Command CheckBill { get; }
        public Command SelectCategory { get; }
        public Command SelectWallet { get; }

        public event EventHandler<Bill> BillChecked;

        private readonly Bill bill;
        private readonly DateTime createDate;

        private int walletId;
        private int categoryId;

        public AddBillPage(DateTime date)
        {
            createDate = date;
            CheckBill = new Command(OnCheckBill);
            SelectCategory = new Command(OnSelectCategory);
            SelectWallet = new Command(OnSelectWallet);
            InitializeComponent();
            Title = Resource.AddBill;

            Initial();
        }

        public AddBillPage(Bill bill)
        {
            this.bill = bill;
            CheckBill = new Command(OnCheckBill);
            SelectCategory = new Command(OnSelectCategory);
            SelectWallet = new Command(OnSelectWallet);
            InitializeComponent();
            Title = Resource.EditBill;

            Initial();
        }

        private void Initial()
        {
            if (bill != null)
            {
                Amount = Math.Abs(bill.Amount).ToString(CultureInfo.InvariantCulture);
                Name = bill.Name;
                walletId = bill.WalletId;
                categoryId = bill.CategoryId;
                SetValue(WalletNameProperty, App.Accounts.FirstOrDefault(a => a.Id == walletId)?.Name);
                SetValue(CategoryNameProperty, App.Categories.FirstOrDefault(c => c.Id == categoryId)?.Name);
                Store = bill.Store;
                CreatedDate = bill.CreateTime.Date;
                CreatedTime = bill.CreateTime.TimeOfDay;
                Note = bill.Note;
            }
            else
            {
                var first = App.Accounts.First();
                walletId = first.Id;
                SetValue(WalletNameProperty, first.Name);
                var firstCategory = App.Categories.First();
                categoryId = firstCategory.Id;
                SetValue(CategoryNameProperty, firstCategory.Name);
                CreatedDate = createDate.Date;
                CreatedTime = DateTime.Now.TimeOfDay;
            }
        }

        private async void OnCheckBill()
        {
            if (Tap.IsBusy)
            {
                return;
            }
            using (Tap.Start())
            {
                if (!decimal.TryParse(Amount, out decimal amount))
                {
                    return;
                }
                if (amount == 0)
                {
                    await this.ShowMessage(Resource.AmountRequired);
                    return;
                }
                amount = Math.Abs(amount);
                var category = App.Categories.FirstOrDefault(c => c.Id == categoryId);
                if (category.Type == CategoryType.Spending)
                {
                    amount *= -1;
                }
                await Navigation.PopAsync();
                var name = Name;
                if (string.IsNullOrWhiteSpace(name))
                {
                    name = category.Name;
                }
                if (bill != null)
                {
                    bill.Amount = amount;
                    bill.Name = name;
                    bill.CategoryId = categoryId;
                    bill.WalletId = walletId;
                    bill.CreateTime = CreatedDate.Date.Add(CreatedTime);
                    bill.Store = Store;
                    bill.Note = Note;
                }
                BillChecked?.Invoke(this, bill ?? new Bill
                {
                    Id = -1,
                    Amount = amount,
                    Name = name,
                    CategoryId = categoryId,
                    WalletId = walletId,
                    CreateTime = CreatedDate.Date.Add(CreatedTime),
                    Store = Store,
                    Note = Note
                });
            }
        }

        private async void OnSelectCategory()
        {
            if (Tap.IsBusy)
            {
                return;
            }
            using (Tap.Start())
            {
                var source = App.Categories.Select(c => new SelectItem<int>
                {
                    Value = c.Id,
                    Name = c.Name,
                    Icon = c.Icon
                });
                var page = new ItemSelectPage<SelectItem<int>>(source);
                page.ItemTapped += Category_ItemTapped;
                await Navigation.PushAsync(page);
            }
        }

        private void Category_ItemTapped(object sender, SelectItem<int> category)
        {
            categoryId = category.Value;
            SetValue(CategoryNameProperty, category.Name);
        }

        private async void OnSelectWallet()
        {
            if (Tap.IsBusy)
            {
                return;
            }
            using (Tap.Start())
            {
                var source = App.Accounts.Select(a => new SelectItem<int>
                {
                    Value = a.Id,
                    Name = a.Name,
                    Icon = a.Icon
                });
                var page = new ItemSelectPage<SelectItem<int>>(source);
                page.ItemTapped += Wallet_ItemTapped;
                await Navigation.PushAsync(page);
            }
        }

        private void Wallet_ItemTapped(object sender, SelectItem<int> account)
        {
            walletId = account.Value;
            SetValue(WalletNameProperty, account.Name);
        }
    }
}