using System;
using System.Collections.Generic;

namespace InABox.Mail
{
    public abstract class CoreMailer<TFolderType, TSummaryType, TMessageType> : ICoreMailer, IDisposable where TFolderType : ICoreMailFolder
        where TSummaryType : ICoreMailSummary
        where TMessageType : ICoreMailMessage
    {
        #region Public Properties

        public string MailboxHost { get; set; }
        public int MailboxPort { get; set; }
        public string MailboxDomain { get; set; }
        public string MailboxUserName { get; set; }
        public string MailboxPassword { get; set; }

        public string SMTPHost { get; set; }
        public int SMTPPort { get; set; }
        public string SMTPDomain { get; set; }
        public string SMTPUserName { get; set; }
        public string SMTPPassword { get; set; }

        #endregion

        #region Public Methods

        public bool Connect()
        {
            return DoConnect();
        }

        public bool IsConnected => GetIsConnected();

        public ICoreMailMessage CreateMessage()
        {
            return DoCreateMessage();
        }

        public ICoreMailFolder FindFolder(ICoreMailFolder folder, string name)
        {
            return DoFindFolder((TFolderType)folder, name);
        }

        public ICoreMailFolder Inbox => GetInbox();

        public ICoreMailFolder SentItems => GetSentItems();

        public IEnumerable<ICoreMailMessage> GetMessages(ICoreMailFolder folder)
        {
            return DoGetMessages((TFolderType)folder) as IEnumerable<ICoreMailMessage>;
        }

        public ICoreMailMessage GetMessage(ICoreMailFolder folder, string id)
        {
            return DoGetMessage((TFolderType)folder, id);
        }

        public IEnumerable<ICoreMailSummary> ListMessages(ICoreMailFolder folder, int min = 0, int max = int.MaxValue)
        {
            return DoListMessages((TFolderType)folder, min, max) as IEnumerable<ICoreMailSummary>;
        }

        public bool MoveMessage(ICoreMailMessage message, ICoreMailFolder to)
        {
            return DoMoveMessage((TMessageType)message, (TFolderType)to);
        }

        public bool SendMessage(ICoreMailMessage message)
        {
            return DoSendMessage((TMessageType)message);
        }

        public bool SaveDraft(ICoreMailMessage message)
        {
            return DoSaveDraft((TMessageType)message);
        }

        #endregion

        #region Setup / Teardown

        public CoreMailer()
        {
            Initialize();
        }

        protected abstract void Initialize();

        public abstract void Dispose();

        #endregion

        #region Protected/Abstract Methods

        protected abstract bool DoConnect();

        protected abstract bool GetIsConnected();

        protected abstract TFolderType DoFindFolder(TFolderType folder, string name);

        protected abstract TFolderType GetInbox();

        protected abstract TFolderType GetSentItems();

        protected abstract TMessageType DoGetMessage(TFolderType folder, string id);

        protected abstract IEnumerable<TMessageType> DoGetMessages(TFolderType folder);

        protected abstract IEnumerable<TSummaryType> DoListMessages(TFolderType folder, int min = 0, int max = int.MaxValue);

        protected abstract TMessageType DoCreateMessage();

        protected abstract bool DoMoveMessage(TMessageType message, TFolderType to);

        protected abstract bool DoSendMessage(TMessageType message);

        protected abstract bool DoSaveDraft(TMessageType message);

        #endregion
    }
}