using System;
using System.Collections.Generic;
using System.Linq;
using KellermanSoftware.ContactsModule.Models;

namespace KellermanSoftware.ContactsModule.DataAccess
{
    public class MockRepository : IRepository
    {
        private List<Contact> _contactList;

        public MockRepository()
        {
            CreateDatabaseIfItDoesntExist();
        }

        public void CreateDatabaseIfItDoesntExist()
        {
            if (_contactList == null)
            {
                _contactList = new List<Contact>();
                _contactList.Add(new Contact 
                                     { 
                                         ContactId = 1,
                                         Name = "John Smith",
                                         Address = "123 Main Street",
                                         Email = "john.smith@hotmail.com",
                                         Phone = "(614) 867-5309"
                                     });
                _contactList[0].History.Add(new ContactHistory
                                                {
                                                    ContactHistoryId = 1,
                                                    ContactType = "Phone",
                                                    Note = "Called John at home"
                                                });
                _contactList.Add(new Contact
                                     {
                                         ContactId = 2,
                                         Name = "Jane Doe",
                                         Address = "467 Maple Avenue",
                                         Email = "jdoe@gmail.com",
                                         Phone = "(614) 555-7575"
                                     });
            }
        }

        public void DeleteHistory(ContactHistory history)
        {
            foreach (var contact in _contactList)
            {
                var historyToDelete = 
                    contact.History.Find(x => x.ContactHistoryId == history.ContactHistoryId);
                if (historyToDelete != null)
                {
                    contact.History.Remove(historyToDelete);
                    break;
                }
            }
        }

        public void DeleteContact(long primaryKey)
        {
            foreach (Contact contact in _contactList.ToList())
            {
                if (contact.ContactId == primaryKey)
                {
                    _contactList.Remove(contact);
                }
            }
        }

        public void SaveContact(Contact contact)
        {
            if (contact.ContactId == 0)
            {
                contact.ContactId = GetNextContactId();
                _contactList.Add(contact);
            }
            else
            {
                int index =
                    _contactList.FindIndex(x => x.ContactId == contact.ContactId);
                if (index != -1)
                {
                    _contactList[index] = contact; 
                }
            }

            foreach (var contactHistory in contact.History)
            {
                if (contactHistory.ContactHistoryId == 0)
                {
                    contactHistory.ContactHistoryId = GetNextContactHistoryId();
                }
            }
        }

        public Contact LoadContact(long primaryKey)
        {
            return _contactList.FirstOrDefault(o => o.ContactId == primaryKey);
        }

        public List<ContactName> LoadContactNames()
        {
            var query = from contact in _contactList
                        select new ContactName
                                   {
                                       ContactId = contact.ContactId,
                                       Name = contact.Name
                                   };
            return query.ToList();
        }

        private int GetNextContactId()
        { 
            return _contactList.Count == 0
                       ? 1
                       : _contactList.Max(x => x.ContactId) + 1;
        }

        private int GetNextContactHistoryId()
        {
            Func<int, Contact, int> calculateMaxContactHistoryId =
                (currentMax, contact) =>
                    contact.History.Count == 0
                        ? currentMax
                        : Math.Max(currentMax, 
                                   contact.History.Max(x => x.ContactHistoryId));

            int maxId = _contactList.Aggregate(0, calculateMaxContactHistoryId);
            return maxId + 1;
        }
    }
}
