using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Pluto.Api;
using McKesson.PPS.Fusion.Authentication.Business;
using McKesson.PPS.Fusion.Communications.Business.Folders;
using McKesson.PPS.Fusion.Communications.Business;
using McKesson.PPS.Fusion.Communications.Business.Commands;
using McKesson.PPS.Fusion.Communications.Business.FolderContents;
using McKesson.PPS.Fusion.Communications.Data.Service;
using McKesson.PPS.Fusion.Communications.Business.FolderContents.Edit;
using McKesson.PPS.Fusion.Communications.Business.FolderContents.Recepients;
using McKesson.PPS.Fusion.Communications.Business.Lookups;
using McKesson.PPS.Fusion.Communications.Data.Entity;
using McKesson.PPS.Fusion.Business.Shared.Communications;

namespace PlutoServer.PracticeChoice.Core {
    public class Provider {

        public void SendMessage(string authToken, MessageInfo1 message) { 
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);
                Csla.ApplicationContext.User = principal;
                
                var msg = Message.NewMessage();
                msg.ActivateDate = DateTime.Now;
                msg.Body = message.Body;
                msg.Subject = message.Subject;
                foreach(var item in message.ToList) {
                    var recipient = RecepientPerson.CreateNewInstance(item.Id);
                    msg.ToList.Add(recipient);
                }
                
                msg.Priority = new McKesson.PPS.Fusion.Communications.Business.Lookups.PriorityType(1, "Default");

                msg.SendMessage(false);
            }
        }

        public IList<MailboxFolderInfo1> GetMailboxFoldersInfo(string authToken, int providerId) {
            IList<MailboxFolderInfo1> foldersInfoList = null;
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);
                Csla.ApplicationContext.User = principal;

                var folderList = FolderList.GetFolders();
                if(folderList != null) {
                    foldersInfoList = new List<MailboxFolderInfo1>();
                    foreach(var folder in folderList) {
                        foldersInfoList.Add(new MailboxFolderInfo1() { 
                            Name = folder.DisplayName,
                            ReadCount = folder.ReadCount,
                            TotalCount = folder.TotalCount,
                            Type = (MailboxFolderTypeEnum)folder.FolderType
                        });    
                    }
                }
            }
            return foldersInfoList;
        }

        public MessageInfo1 GetMessage(string authToken, long messageId) {
            MessageInfo1 messageInfo = null;
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);
                Csla.ApplicationContext.User = principal;
                var msgId = (int)messageId;
                var msg = Message.Get(msgId);
                if(msg != null) {
                    var bccList = this.GetMessageRecipientList(msg.BccList);
                    var ccList = this.GetMessageRecipientList(msg.CcList);
                    var toList = this.GetMessageRecipientList(msg.ToList);
                    messageInfo = new MessageInfo1() {
                        BccList = bccList == null? null : bccList.ToArray<MessageRecipientInfo1>(),
                        Body = msg.Body,
                        CcList = ccList == null ? null : ccList.ToArray<MessageRecipientInfo1>(),
                        ChartId = msg.ChartId.HasValue?msg.ChartId.Value:0,
                        DateSent = msg.DateSent,
                        From = msg.FromText,
                        HeaderId = msg.HeaderId,
                        IsReceiptRequired = msg.IsReceiptRequired,
                        IsRecorded = msg.IsRecorded,
                        MessageSendType = (MessageSendTypeEnum)msg.MessageSendType,
                        PatientId = msg.PatientId,
                        SenderId = msg.SenderId,
                        ToList = toList == null?null:toList.ToArray<MessageRecipientInfo1>() 
                    };
                }
            }
            return messageInfo;
        }

        private IList<MessageRecipientInfo1> GetMessageRecipientList(RecepientList recipientList) {
            IList<MessageRecipientInfo1> list = null;
            if((recipientList != null) && (recipientList.Count > 0)) {
                list = new List<MessageRecipientInfo1>();
                foreach(var item in recipientList) {
                    list.Add(new MessageRecipientInfo1() {
                        Id = item.ID,
                        Name = item.DisplayName
                    });
                }
            }
            return list;
        }

        private FolderCriteria GetFolderCriteria(MagicIdentity identity, MailboxFolderTypeEnum folderType) {
            FolderCriteria folderCriteria = null;
            switch(folderType) {
                case MailboxFolderTypeEnum.Inbox:
                    folderCriteria = new InboxFolderCriteria(identity.PersonId, identity.PracticeId);
                    break;
                case MailboxFolderTypeEnum.Sent:
                    folderCriteria = new SentFolderCriteria(identity.PersonId, identity.PracticeId);
                    break;
                case MailboxFolderTypeEnum.Saved:
                    folderCriteria = new SavedFolderCriteria(identity.PersonId, identity.PracticeId);
                    break;
                case MailboxFolderTypeEnum.Done:
                    folderCriteria = new DoneFolderCriteria(identity.PersonId, identity.PracticeId);
                    break;
                case MailboxFolderTypeEnum.Outbox:
                    folderCriteria = new OutboxFolderCriteria(identity.PersonId, identity.PracticeId);
                    break;
                case MailboxFolderTypeEnum.Draft:
                    folderCriteria = new DraftFolderCriteria(identity.PersonId, identity.PracticeId);
                    break;
                default:
                    break;
            }
            return folderCriteria;
        }
        
        public IList<FolderItemInfo1> GetMailboxItems(string authToken, MailboxFolderTypeEnum folderType) {
            IList<FolderItemInfo1> itemsList = null;
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);
                Csla.ApplicationContext.User = principal;
                var criteria = this.GetFolderCriteria(identity, folderType);
                Dictionary<string, object> args = new Dictionary<string, object>()
			    {
				    { "criteria", criteria  }
			    };

                using(var ds = DataServiceLocator.Resolve<IFolderItemDataService>(args)) {
                    var result = ds.GetFolderItems();

                    if(result != null) {
                        itemsList = new List<FolderItemInfo1>();
                        switch(folderType) {
                            case MailboxFolderTypeEnum.Inbox:
                                LoadMailboxFolderItems<InboxFolderItem>(itemsList, result);
                                break;
                            case MailboxFolderTypeEnum.Sent:
                                LoadMailboxFolderItems<SentFolderItem>(itemsList, result);
                                break;
                            case MailboxFolderTypeEnum.Saved:
                                LoadMailboxFolderItems<SavedFolderItem>(itemsList, result);
                                break;
                            case MailboxFolderTypeEnum.Done:
                                LoadMailboxFolderItems<DoneFolderItem>(itemsList, result);
                                break;
                            case MailboxFolderTypeEnum.Outbox:
                                LoadMailboxFolderItems<OutboxFolderItem>(itemsList, result);
                                break;
                            case MailboxFolderTypeEnum.Draft:
                                LoadMailboxFolderItems<DraftFolderItem>(itemsList, result);
                                break;
                            default:
                                break;
                        }      
                    }
                }
            }
            return itemsList;
        }

        private Dictionary<Type, Func<FolderItem, IMailboxItem>> FolderItemFactories {
            get {
                var factory = new Dictionary<Type, Func<FolderItem, IMailboxItem>>();
                factory.Add(typeof(InboxFolderItem), (data) => InboxFolderItem.GetInstance(data));
                factory.Add(typeof(SentFolderItem), (data) => SentFolderItem.GetInstance(data));
                factory.Add(typeof(DoneFolderItem), (data) => DoneFolderItem.GetInstance(data));
                factory.Add(typeof(SavedFolderItem), (data) => SavedFolderItem.GetInstance(data));
                factory.Add(typeof(OutboxFolderItem), (data) => OutboxFolderItem.GetInstance(data));
                factory.Add(typeof(DraftFolderItem), (data) => DraftFolderItem.GetInstance(data));
                return factory;
            }
        }

        private void LoadMailboxFolderItems<TFolderItemType>(IList<FolderItemInfo1> inboxItemsList, 
            IList<FolderItem> folderItemsList)
            where TFolderItemType : ReadOnlyMailboxItem<TFolderItemType> {

            foreach(var folderItemData in folderItemsList) {
                var item = (TFolderItemType)FolderItemFactories[typeof(TFolderItemType)].Invoke(folderItemData);
                var folderItemInfo = GetFolderItemInfo<TFolderItemType>(item);
                folderItemInfo.To = GetTo<TFolderItemType>(item);
                inboxItemsList.Add(folderItemInfo);
            }
        }
        
        private MessageRecipientInfo1 GetSender<T>(ReadOnlyMailboxItem<T> mailboxItem) where T : ReadOnlyMailboxItem<T> {
            var recipient = (RecepientPerson)mailboxItem.Sender;
            return new MessageRecipientInfo1() {
                Id = recipient.ID,
                Name = recipient.DisplayName
            };
        }

        private string GetTo<T>(T mailboxItem)  {
            var messageTo = string.Empty;
            if(typeof(T).IsAssignableFrom(typeof(SentFolderItem))) {
                messageTo = ((SentFolderItem)((object)mailboxItem)).ToName;
            }else if(typeof(T).IsAssignableFrom(typeof(DoneFolderItem))){
                messageTo = ((DoneFolderItem)((object)mailboxItem)).ToName;
            } else if (typeof(T).IsAssignableFrom(typeof(DraftFolderItem))){
                messageTo = ((DraftFolderItem)((object)mailboxItem)).ToNames;
            } else if (typeof(T).IsAssignableFrom(typeof(SavedFolderItem))){
                messageTo = ((SavedFolderItem)((object)mailboxItem)).ToName;
            } else if(typeof(T).IsAssignableFrom(typeof(OutboxFolderItem))){
                messageTo = ((OutboxFolderItem)((object)mailboxItem)).ToNames;
            }
            return messageTo;
        }

        private FolderItemInfo1 GetFolderItemInfo<T>(ReadOnlyMailboxItem<T> item) where T : ReadOnlyMailboxItem<T> {
            return new FolderItemInfo1() {
                CategoryType = (MessageCategoryEnum)item.CategoryType,
                ChartId = item.ChartId.HasValue ? item.ChartId.Value : 0,
                DateTransceived = item.DateTransceived,
                FolderType = (MailboxFolderTypeEnum)item.FolderLocation,
                From = item.FromText,
                Id = item.Id,
                IsRead = item.IsRead,
                PatientId = item.PatientId,
                PatientName = item.PatientName,
                Priority = item.PriorityName,
                SentDate = item.SentDate,
                Subject = item.Subject,
                Sender = GetSender<T>(item)
            };

        }

    }
}
