#!/usr/bin/env python3
from csv import DictReader
import argparse
import datetime
import json
import requests
import sys


class Counter:
    """ Counts for us """
    COUNT = 0

    def __getitem__(self, name):
        """ Get next count index """
        self.COUNT = self.COUNT + 1
        return self.COUNT


COUNTERS = Counter()


def is_overflow(record):
    """ Is this an overflow ticker """
    return record["Item"] == "Overflow"


def get_type(record):
    """ Get the type of the record """
    tpe = record["Item"] if not is_overflow(record) else record["Location"]
    tpe = tpe if tpe else ""
    return tpe.replace("Stitcher", "Stitch")


def get_id(record):
    """ Get the ID of a record"""
    tpe = get_type(record)
    return f"{tpe}-{'O' if is_overflow(record) else '-P' }{COUNTERS[tpe]}".strip()


REPAIR_FIELD_MAP = {
    "id": get_id,
    "name": lambda record: f"{record['First Name']} {record['Last Name']}".strip(),
    "email": "Email",
    "phone": "Phone",
    "type": get_type,
    "item": "Sign Up Comment",
    "subtype": lambda _: "N/A",
    "description": "Description",
    "repairers": lambda _: [],
    "stateIndex": lambda _: 0,
    "reserved": lambda _: True
}


def get_team(record):
    """ Get the team from the RC sign-up """
    team = record.get("Which team would you like to be on for this Repair Cafe?", "None")
    for possible in ["Tinker", "Stitch", "Knife"]:
        if team.lower().startswith(possible.lower()):
            return possible
    return "Other"


VOLUNTEER_FIELD_MAP = {
    "id": lambda record: f"repairer-{COUNTERS['repairers']}",
    "name": lambda record: f"{record['First Name']} {record['Last Name']}".strip(),
    "email": "Email Address",
    "team": get_team,
    "skills": lambda _: []
}


def get_string_value(record, transform):
    """ Get string value """
    value = record[transform]
    return value.strip() if value else ""


def get_value(key, record, field_map):
    """ Get the value of a key from a record """
    transform = field_map[key]
    return get_string_value(record, transform) if isinstance(transform, str) else transform(record)


def validate(parser, args):
    """ Validate args, exiting on failure"""
    try:
        datetime.datetime.strptime(args.date, "%Y-%m-%d")
    except ValueError:
        print(f"[ERROR] {args.date} not in format YYYY-MM-DD\n", file=sys.stderr)
    try:
        response = requests.get(args.url)
        response.raise_for_status()
        if response.json().get("tagline", "Nope") != "You Know, for Search":
            raise Exception("Not elasticsearch")
    except:
        print(f"[ERROR] {args.url} does not appear to be a valid ElasticSearch database\n", file=sys.stderr)
        parser.print_help()
        sys.exit(1)


def parse_arguments():
    """ Parse the arguments to this program """
    parser = argparse.ArgumentParser(description='Pre-populate pre-registrants into the rc database')
    parser.add_argument('csv_file', type=argparse.FileType('r'), help='CSV file to process into records')
    parser.add_argument('--type', default="repairs", choices=['repairs', 'repairers'], help='Type to pre-populate')
    parser.add_argument('--date', default=datetime.datetime.now().strftime("%Y-%m-%d"),
                        help='Date of the event to pre-populate in YYYY-MM-DD')
    parser.add_argument('--url', default='http://app.repair-cafe-pasadena.org/elastic/', help='Base url of database')
    args = parser.parse_args()
    validate(parser, args)
    return args


def setup_index(index_url):
    """ Setup an index """

    response = requests.put(index_url)
    error_type = response.json().get("error", {}).get("root_cause", [{}])[0].get("type", "")
    if response.status_code != 200 and error_type != "resource_already_exists_exception":
        print(f"[ERROR] {response.text}. Exiting", file=sys.stderr)
        sys.exit(1)


def main():
    """ Hi Lewis!!! """
    args = parse_arguments()
    index_url = f"{args.url}/{args.type}-{args.date}"
    item_url = f"{index_url}/{args.type.rstrip('s')}/{{id}}"

    field_map = REPAIR_FIELD_MAP if args.type == "repairs" else VOLUNTEER_FIELD_MAP

    # Step 0: read CSV file
    csv_handle = DictReader(args.csv_file)

    # Step 1: guarantee the index exists
    setup_index(index_url)

    # Step 3: convert CSV to valid items to post
    items = [{key: get_value(key, record, field_map) for key in field_map.keys()} for record in csv_handle]
    filtered = [item for item in items if item["name"] and item.get("type", "yup")]

    # Step 4: post all the items
    for item in filtered:
        try:
            specific_url = item_url.format(id=item['id'])
            response = requests.post(specific_url, data=json.dumps(item),
                                     headers={"Content-Type": "application/json"})
            response.raise_for_status()
        except:
            print(f"[ERROR] {response.text}", file=sys.stderr)


if __name__ == "__main__":
    main()
