"""Functions for posting data to carbon"""

import socket
import time
import random
from typing import Optional, List

RELAY_PORTS = [2003, 2005, 2007, 2009]


def carbon_post(
    data: List[str],
    server: str = 'graphite.imhadmin.net',
    port: Optional[int] = None,
    chunk_size: int = 500,
    chunk_sleep: float = 0.2,
    max_tries: int = 3,
) -> bool:
    """Post all items in a list of strings to Carbon

    Args:
        data: lines to post, each formatted ``"bucket.name value timestamp"``
        server: graphite server FQDN to post to
        port: TCP port to post to; if unspecified, a random port
            from ``mtrlib.carbon.RELAY_PORTS`` will be used
        chunk_size: how many metrics to post in each HTTP POST request
        chunk_sleep: how long in seconds to pause between HTTP POSTs
        max_tries: how many times to retry on socket.error
    Returns:
        a bool of whether the posts succeeded
    """
    if port is None:
        port = random.choice(RELAY_PORTS)
    if not isinstance(data, list):
        raise ValueError('carbon_post data must be a list')
    to_carbon = data[:]  # create a new copy in memory
    success = True
    while to_carbon and success:
        chunk = []
        for _ in range(chunk_size):
            try:
                chunk.append(to_carbon.pop(0))
            except IndexError:
                continue
        for attempt in range(max_tries):  # attempt to post it 3 times
            try:
                sock = socket.socket()
                sock.connect((server, port))
                payload = '{0}\n'.format('\n'.join(chunk))
                sock.sendall(bytes(payload, 'ascii', 'ignore'))
                sock.close()
                success = True
                break  # stop trying
            except IOError:
                success = False
                if attempt < max_tries - 1:
                    time.sleep(chunk_sleep)
        if to_carbon:
            time.sleep(chunk_sleep)
    return success
