using System;
using System.Data.Entity;
using System.Data.Entity.Core;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Transactions;
using System.Windows.Forms;
using AdvertisingProfitControlData;

namespace AdvertsingProfitControl
{
    public partial class FrmManageAdItems : Form
    {
        private bool _isUpdating;
        private bool _replaceingReference;
        private AdItem _replacee;

        public FrmManageAdItems()
        {
            InitializeComponent();
            newItemTextBox.TextChanged += NewItemTextChanged;
            adItemsListView.ItemSelectionChanged += UpdateAdItemTextFields;
            var columnHeader = new ColumnHeader
            {
                Name = "AdItemHeaderColumn",
                Width = Width / 2
            };
            adItemsListView.Columns.Add(columnHeader);
            RefreshAdItemListing();
        }

        private void FilterValueChanged(object sender, EventArgs e)
        {
            if(filterComboBox.Enabled == false) return;
            if (!_replaceingReference)
            {
                adItemsListView.Columns[0].Text = @"Current Ad Items (" + (filterComboBox.SelectedItem.ToString() == "All" ? "No Filter" : @"Filter " + filterComboBox.SelectedItem) + @"):";
            }
            else
            {
                adItemsListView.Columns[0].Text = @"Chose Replacement (" + (filterComboBox.SelectedItem.ToString() == "All" ? "No Filter" : @"Filter " + filterComboBox.SelectedItem) + @"):";
            }
            adItemsListView.Items.Clear();
            var db = new AdvertisingProfitControlDbContext();
            var adItems = db.AdItems.Select(x => x);
            foreach (var adItem in adItems)
            {
                if(_replacee != null && _replacee.Name == adItem.Name) continue;
                var item = new ListViewItem
                {
                    Text = adItem.Name,
                    Tag = adItem
                };

                if (string.Equals(filterComboBox.SelectedItem.ToString(), "All", StringComparison.Ordinal))
                {
                    adItemsListView.Items.Add(item);
                    continue;
                }

                if (string.Equals(filterComboBox.SelectedItem.ToString(), "0-9", StringComparison.Ordinal) && char.IsNumber(adItem.Name[0]))
                {
                    adItemsListView.Items.Add(item);                    
                }
                else if (!string.Equals(filterComboBox.SelectedItem.ToString(), "0-9", StringComparison.Ordinal) && char.IsLetter(adItem.Name[0]))
                {
                    if(filterComboBox.SelectedItem.ToString()[0] == adItem.Name[0])
                    { adItemsListView.Items.Add(item);}
                }
            }
            if (!_replaceingReference)
            {
                newItemTextBox.Text = string.Empty;
                descriptionTextBox.Text = string.Empty;
                removeAdItemButton.Enabled = false;
            }

        }

        private void UpdateAdItemTextFields(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            _isUpdating = true;
            removeAdItemButton.Enabled = true;
            if (!_replaceingReference)
            {
                newItemTextBox.Text = ((AdItem)e.Item.Tag).Name;
                descriptionTextBox.Text = ((AdItem)e.Item.Tag).Description;
                replaceReferencesButton.Enabled = true;
                addUpdateItemButton.Text = @"Update Ad Item";
                newItemLabel.Text = @"Update Ad Item:";
            }
            else
            {
                descriptionTextBox.Text = ((AdItem)e.Item.Tag).Name;
                addUpdateItemButton.Enabled = true;
            }
        }

        private void NewItemTextChanged(object sender, EventArgs e)
        {
            if (_isUpdating && newItemTextBox.Text.Length == 0)
            {
                _isUpdating = false;
                descriptionTextBox.Text = string.Empty;
                if (!_replaceingReference)
                {
                    addUpdateItemButton.Text = @"Register Ad Item";
                    newItemLabel.Text = @"Register New Ad Item:";
                    removeAdItemButton.Enabled = false;
                    replaceReferencesButton.Enabled = false;
                }
            }
            addUpdateItemButton.Enabled = newItemTextBox.Text.Length > 0;
        }

        private void RefreshAdItemListing(string filter = "")
        {
            filterComboBox.SelectedIndexChanged -= FilterValueChanged;
            //Check to see if the current view is empty.
            if (adItemsListView.Items.Count == 0) filter = string.Empty;
            adItemsListView.Items.Clear();
            filterComboBox.Items.Clear();
            filterComboBox.Items.Add("All");
            var db = new AdvertisingProfitControlDbContext();
            var adItems = db.AdItems.Select(x => x).OrderBy(x => x.Name);
            var adItemCount = 0;
            var numberFound = false;
            foreach (var adItem in adItems)
            {
                if(_replacee != null && _replacee.Name == adItem.Name) continue;
                var item = new ListViewItem
                {
                    Text = adItem.Name,
                    Tag = adItem
                };
                if (filter == string.Empty || filter == "All")
                {
                    adItemsListView.Items.Add(item);
                }
                else if (string.Equals(adItem.Name[0].ToString(), filter, StringComparison.CurrentCultureIgnoreCase))
                {
                    adItemsListView.Items.Add(item);
                }
                else if (filter == "0-9" && char.IsNumber(adItem.Name[0]))
                {
                    adItemsListView.Items.Add(item);
                }
                //Populate the filter.
                if (!filterComboBox.Items.Contains(adItem.Name[0].ToString()))
                {
                    if (char.IsDigit(adItem.Name[0]) && !numberFound)
                    {
                        filterComboBox.Items.Add("0-9");
                        numberFound = true;
                    }
                    else
                    {
                        filterComboBox.Items.Add(adItem.Name[0].ToString());                        
                    }
                }
                adItemCount++;
            }

            if (adItemCount > 0)
            {
                filterComboBox.Enabled = true;
                filterComboBox.SelectedIndex = filterComboBox.Items.Contains(filter) ? filterComboBox.Items.IndexOf(filter) : 0;
                adItemsListView.Columns[0].Text = @"Current Ad Items (" + (filterComboBox.SelectedItem.ToString() == "All" ? "No Filter" : @"Filter " + filterComboBox.SelectedItem) + @"):";
            }
            else
            {
                adItemsListView.Columns[0].Text = @"No Ad Items to Display.";
                filterComboBox.Enabled = false;
                filterComboBox.SelectedIndex = 0;
            }
            if (!_replaceingReference)
            {
                removeAdItemButton.Enabled = false;
                newItemTextBox.Text = string.Empty;
                descriptionTextBox.Text = string.Empty;
            }
            filterComboBox.SelectedIndexChanged += FilterValueChanged;
        }

        private void RemoveSelectedAdItem(object sender, EventArgs e)
        {
            if (_replaceingReference)
            {
                SetFormStateAdNewItem();
                return;
            }
            var item = adItemsListView.SelectedItems[0];
            var oldAdItem = (AdItem)item.Tag;
            var db = new AdvertisingProfitControlDbContext();
            var adItemEntry = db.AdItems.Single(x => x.Id == oldAdItem.Id);
            //Check to see if the ad special is used by other tables.
            if (adItemEntry.ActualSales.Count > 0 && !_replaceingReference)
            {
                //If so, display a warning to the user about the potential data loss.
                var result =
                    MessageBox.Show(
                        adItemEntry.ActualSales.Count +
                        @" reference(s) to this item found. Do you want to delete these records? This can not be undone.",
                        @"References to " + oldAdItem.Name + @" Found", MessageBoxButtons.YesNoCancel,
                        MessageBoxIcon.Question);
                if (result != DialogResult.Yes) return;
                //Perform the necessary operations to remove all references to the key word.
                using (var scope = new TransactionScope())
                {
                    try
                    {
                        db.Projections.RemoveRange(db.Projections.Where(x => x.FkAdItemId == oldAdItem.Id));
                        db.Inventories.RemoveRange(db.Inventories.Where(x => x.FkAdItemId == oldAdItem.Id));
                        db.ActualSales.RemoveRange(db.ActualSales.Where(x => x.FkAdItemId == oldAdItem.Id));
                        db.AdItems.Remove(adItemEntry);
                        db.SaveChanges();
                        scope.Complete();
                        informationLabel.Text = @"Removed '" + Environment.NewLine + oldAdItem.Name +
                                                Environment.NewLine + @"' successfully.";
                        adItemsListView.Items.RemoveAt(adItemsListView.SelectedItems[0].Index);
                    }
                    catch (DbUpdateException ex)
                    {
                        informationLabel.Text = @"Failed to remove " + Environment.NewLine + oldAdItem.Name + @"." +
                                                Environment.NewLine + ex.Message;
                    }
                }
            }
            else
            {
                try
                {
                    db.AdItems.Remove(adItemEntry);
                    db.SaveChanges();
                    informationLabel.Text = @"Removed '" + Environment.NewLine + oldAdItem.Name +
                                            Environment.NewLine + @"' successfully.";
                    adItemsListView.Items.RemoveAt(adItemsListView.SelectedItems[0].Index);
                }
                catch (DbUpdateException ex)
                {
                    informationLabel.Text = @"Failed to remove " + Environment.NewLine + oldAdItem.Name + @"." + Environment.NewLine + ex.Message;
                }
            }
            RefreshAdItemListing(filterComboBox.SelectedItem.ToString());
        }

        private void AddUpdateItem(object sender, EventArgs e)
        {
            var db = new AdvertisingProfitControlDbContext();
            if (!_isUpdating)
            {
                newItemTextBox.Text = TextFormat.FormatAdItemText(newItemTextBox.Text);
                if (!db.AdItems.Any(x => x.Name == newItemTextBox.Text))
                {
                    var adItem = new AdItem
                    {
                        Name = newItemTextBox.Text,
                        Description = descriptionTextBox.Text
                    };
                    db.AdItems.Add(adItem);
                    try
                    {
                        db.SaveChanges();
                        informationLabel.Text = @"Registered '" + Environment.NewLine + adItem.Name + Environment.NewLine + @"' successfully.";
                    }
                    catch (DbUpdateException ex)
                    {
                        informationLabel.Text = @"Failed to register '" + Environment.NewLine + adItem.Name + @"'." + Environment.NewLine +
                                                ex.Message;
                    }
                }
                else
                {
                    MessageBox.Show(@"Ad item '" + newItemTextBox.Text + @"' already exists.",
                        @"Duplicate Entry", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    newItemTextBox.Text = string.Empty;
                    return;
                }
            }
            else if (_replaceingReference)
            {
                PerformReplacement();
            }
            else
            {
                newItemTextBox.Text = TextFormat.FormatAdItemText(newItemTextBox.Text);
                var item = adItemsListView.SelectedItems[0];
                var index = ((AdItem)item.Tag).Id;
                var adItem = db.AdItems.SingleOrDefault(x => x.Id == index);
                if (adItem == null)
                {
                    informationLabel.Text = @"Failed to retrieve " + Environment.NewLine + @"ad item ID.";
                    return;
                }
                if (!db.AdItems.Any(x => x.Name == newItemTextBox.Text))
                {
                    adItem.Name = newItemTextBox.Text;
                    adItem.Description = descriptionTextBox.Text;
                    db.SaveChanges();
                    informationLabel.Text = @"Updated '" + Environment.NewLine + newItemTextBox.Text + Environment.NewLine + @"' successfully.";
                }
                else
                {
                    MessageBox.Show(@"Ad item '" + newItemTextBox.Text + @"' already exists.",
                        @"Duplicate Name Entered", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }
            }
            RefreshAdItemListing(filterComboBox.SelectedItem.ToString());
        }

        private void FlagFormReplaceRefrence(object sender, EventArgs e)
        {
            SetFormStateReplacingReference();
        }

        private void PerformReplacement()
        {
            var newItem = (AdItem) adItemsListView.SelectedItems[0].Tag;
            var db = new AdvertisingProfitControlDbContext();
            var replacementCount = 0;

            try
            {
                using (var scope = new TransactionScope())
                {
                    var projectionsToUpdate = db.Projections.Where(x => x.AdItem.Id == _replacee.Id);

                    foreach (var record in projectionsToUpdate)
                    {
                        record.FkAdItemId = newItem.Id;
                        db.Projections.Attach(record);
                        db.Entry(record).State = EntityState.Modified;
                        replacementCount++;
                    }

                    var inventoryToUpdate = db.Inventories.Where(x => x.AdItem.Id == _replacee.Id);

                    foreach (var record in inventoryToUpdate)
                    {
                        record.FkAdItemId = newItem.Id;
                        db.Inventories.Attach(record);
                        db.Entry(record).State = EntityState.Modified;
                        replacementCount++;
                    }

                    var actualSalesToUpdate = db.ActualSales.Where(x => x.AdItem.Id == _replacee.Id);

                    foreach (var record in actualSalesToUpdate)
                    {
                        record.FkAdItemId = newItem.Id;
                        db.ActualSales.Attach(record);
                        db.Entry(record).State = EntityState.Modified;
                        replacementCount++;
                    }

                    db.SaveChanges();

                    scope.Complete();
                }
                //All completed without error so give the user the option to delete the replace.
                var result =
                    MessageBox.Show(
                        _replacee.Name + @" has been successfully replaced with " + newItem.Name +
                        @". Would you like to delete " + _replacee.Name + @" from the database?",
                        @"Replacement Completed Successfully on " + replacementCount + @" Item(s)",
                        MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (result == DialogResult.Yes)
                {
                    _replacee = db.AdItems.Single(x => x.Id == _replacee.Id);
                    db.AdItems.Remove(_replacee);
                    db.SaveChanges();
                    informationLabel.Text = @"Removed " + Environment.NewLine + _replacee.Name + Environment.NewLine +
                                            @" from the database.";
                }
                SetFormStateAdNewItem();
                RefreshAdItemListing(filterComboBox.SelectedItem.ToString());
            }
            catch (EntitySqlException e)
            {
                MessageBox.Show(e.Message);
            }
        }

        private void SetFormStateReplacingReference()
        {
            newItemTextBox.TextChanged -= NewItemTextChanged;
            adItemsListView.ItemSelectionChanged -= UpdateAdItemTextFields;
            _replaceingReference = true;
            _replacee = (AdItem)adItemsListView.SelectedItems[0].Tag;
            addUpdateItemButton.Text = @"Replace References";
            addUpdateItemButton.Enabled = false;
            newItemTextBox.Enabled = false;
            newItemLabel.Text = @"Replace";
            descriptionTextBox.Enabled = false;
            descriptionLabel.Text = @"With";
            removeAdItemButton.Text = @"Cancel";
            replaceReferencesButton.Text = @"Select Item to Replace With";
            replaceReferencesButton.Enabled = false;
            //Prevent the user from selecting the same item again.
            adItemsListView.Items.Remove(adItemsListView.SelectedItems[0]);
            if (adItemsListView.Items.Count == 0)
            {
                RefreshAdItemListing();
            }
            newItemTextBox.TextChanged += NewItemTextChanged;
            adItemsListView.ItemSelectionChanged += UpdateAdItemTextFields;
        }

        private void SetFormStateAdNewItem()
        {
            newItemTextBox.TextChanged -= NewItemTextChanged;
            _replacee = null;
            _replaceingReference = false;
            _isUpdating = false;
            newItemTextBox.Enabled = true;
            newItemTextBox.Text = string.Empty;
            descriptionTextBox.Enabled = true;
            descriptionTextBox.Text = string.Empty;
            descriptionLabel.Text = @"Description (Optional):";
            removeAdItemButton.Text = @"Remove Selected Item";
            replaceReferencesButton.Text = @"Replace References With...";
            addUpdateItemButton.Enabled = false;
            addUpdateItemButton.Text = @"Ad New Item";
            newItemLabel.Text = @"Register New Ad Item:";
            removeAdItemButton.Enabled = false;
            replaceReferencesButton.Enabled = false;
            newItemTextBox.TextChanged += NewItemTextChanged;
        }
    }
}
