"""
This script test if swiftsore server have oldest completion too old
"""

import sys
import socket
import eventlet
from swift.cli import recon
from swift.common.ring import RingBuilder
from urllib.parse import urlparse
from oslo_config import cfg
from datetime import datetime, timedelta


# Initialize Swift connection
swiftrecon = recon.SwiftRecon()
pool_size = 30
pool = eventlet.GreenPool(pool_size)

try:
    builder = RingBuilder.load('/etc/swift/object.builder')
except Exception as e:
    sys.exit(e)

# Initialize script arguments
CLI_OPTS = [
    cfg.IntOpt('max_days', default='1', short='D',
               help='Max days for oldest completion. \
                     Sum this with MAX_HOURS'),
    cfg.IntOpt('max_hours', default='0', short='H',
               help='Max hours for oldest completion. \
                     Sum this with MAX_DAYS'),
]


def display_days_hours_for(duration):
    """
    Formatting a datetime object in correct sentence for display
    param duration: datetime object
    return: formatted string
    """
    ret = "for more than"
    if duration.days:
        ret = f"{ret} {duration.days} days"
    if duration.days and duration.seconds:
        ret = f"{ret} and"
    if duration.seconds:
        ret = f"{ret} {int(duration.seconds / 3600)} hours"
    return ret


def _prepare_config():
    """
    Prepare the oslo config
    return: oslo config object
    """
    CONF = cfg.ConfigOpts()
    CONF.register_cli_opts(CLI_OPTS)
    return CONF


def get_hosts():
    """
    Get a list of hosts ip and port
    If script running in a switstore, he check only this server,
    otherwise, he check all cluster
    return: list off tuble with ip and port
    """
    hosts = {}
    devs = [d for d in builder.devs if d]
    # If server have disk, use it, else use all swiftstore
    ip = socket.gethostbyname(socket.gethostname())
    devs_ip = [d for d in devs if d['ip'] == ip]
    if devs_ip:
        devs = devs_ip
    for h in devs:
        # filter only one ip and port by host
        hosts[h['ip']] = h['port']
    return set(hosts.items())


def analyze(max_oldest):
    """
    Analyze all hosts
    param max_oldest: the max oldest tolerate in datetime format
    return: list of swiftstore with their oldest completion is > max_oldest
    """
    hosts = get_hosts()
    scout = recon.Scout(recon_type="replication/object", suppress_errors=True)
    last_stats = []
    for url, response, status, _ts_start, _ts_end \
            in pool.imap(scout.scout, hosts):
        if status == 200:
            last = response.get('replication_last',
                                response.get('object_replication_last', 0))
            oldest = (datetime.now()-datetime.fromtimestamp(last))
            if oldest > max_oldest:
                ip = urlparse(url).hostname
                ho = socket.gethostbyaddr(ip)[0].split('.')[0]
                last_stats.append((f"{ho}", oldest))
    return last_stats


def main():
    """
    Entry point for the script
    """
    CONF = _prepare_config()
    CONF(sys.argv[1:])

    max_oldest = timedelta(days=CONF.max_days, hours=CONF.max_hours)
    ls = analyze(max_oldest)

    # Diplay result
    print(f"### Swift oldest completions {display_days_hours_for(max_oldest)} \
           : {len(ls)} swiftstores")
    for host, ago in sorted(ls, key=lambda x: x[1], reverse=True):
        print(f"- {host}: {display_days_hours_for(ago)}")


if __name__ == "__main__":
    sys.exit(main())
