# Copyright 2015-2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import datetime
import logging

from dateutil.relativedelta import relativedelta

from odoo import fields, models

_logger = logging.getLogger(__name__)


class FetchmailServer(models.Model):
    """Incoming POP/IMAP mail server account."""

    _inherit = "fetchmail.server"

    cleanup_days = fields.Integer(
        string="Expiration days",
        help="Number of days before marking an e-mail as read",
    )

    cleanup_folder = fields.Char(
        string="Expiration folder",
        help="Folder where an e-mail marked as read will be moved.",
    )

    purge_days = fields.Integer(
        string="Deletion days",
        help="Number of days before removing an e-mail",
    )

    @property
    def _server_env_fields(self):
        base_fields = super()._server_env_fields
        mail_cleanup_fields = {
            "cleanup_days": {
                "getter": "getint",
            },
            "purge_days": {
                "getter": "getint",
            },
            "cleanup_folder": {},
        }
        mail_cleanup_fields.update(base_fields)
        return mail_cleanup_fields

    def _cleanup_fetchmail_server(self, server, imap_server):
        count, failed = 0, 0
        expiration_date = datetime.date.today()
        expiration_date -= relativedelta(days=server.cleanup_days)
        search_text = expiration_date.strftime("(UNSEEN BEFORE %d-%b-%Y)")
        imap_server.select()
        result, data = imap_server.search(None, search_text)
        for num in data[0].split():
            try:
                # Mark message as read
                imap_server.store(num, "+FLAGS", "\\Seen")
                if server.cleanup_folder:
                    # To move a message, you have to COPY
                    # then DELETE the message
                    result = imap_server.copy(num, server.cleanup_folder)
                    if result[0] == "OK":
                        imap_server.store(num, "+FLAGS", "\\Deleted")
            except Exception:
                _logger.exception(
                    "Failed to cleanup mail from %s server %s.",
                    server.server_type,
                    server.name,
                )
                failed += 1
            count += 1
        _logger.info(
            "Marked %d email(s) as read on %s server %s;" " %d succeeded, %d failed.",
            count,
            server.server_type,
            server.name,
            (count - failed),
            failed,
        )

    def _purge_fetchmail_server(self, server, imap_server):
        # Purging e-mails older than the purge date, if available
        count, failed = 0, 0
        purge_date = datetime.date.today()
        purge_date -= relativedelta(days=server.purge_days)
        search_text = purge_date.strftime("(BEFORE %d-%b-%Y)")
        imap_server.select()
        result, data = imap_server.search(None, search_text)
        for num in data[0].split():
            try:
                # Delete message
                imap_server.store(num, "+FLAGS", "\\Deleted")
            except Exception:
                _logger.exception(
                    "Failed to remove mail from %s server %s.",
                    server.server_type,
                    server.name,
                )
                failed += 1
            count += 1
        _logger.info(
            "Removed %d email(s) on %s server %s;" " %d succeeded, %d failed.",
            count,
            server.server_type,
            server.name,
            (count - failed),
            failed,
        )

    def fetch_mail(self, raise_exception=True):
        # Called before the fetch, in order to clean up right before
        # retrieving emails.
        for server in self:
            _logger.info(
                "start cleaning up emails on %s server %s",
                server.server_type,
                server.name,
            )
            imap_server = False
            if server.server_type == "imap":
                try:
                    imap_server = server.connect()
                    if server.cleanup_days > 0:
                        self._cleanup_fetchmail_server(server, imap_server)
                    if server.purge_days > 0:
                        self._purge_fetchmail_server(server, imap_server)
                    # Do the final cleanup: delete all messages
                    # flagged as deleted
                    imap_server.expunge()
                except Exception:
                    _logger.exception(
                        "General failure when trying to cleanup"
                        " mail from %s server %s.",
                        server.server_type,
                        server.name,
                    )
                finally:
                    if imap_server:
                        imap_server.close()
                        imap_server.logout()
        return super().fetch_mail(raise_exception)
