# -*- coding: utf-8 -*-

import sys
import yaml
import datetime
import hashlib
from icalendar import Calendar, Event

one_day = datetime.date(1, 1, 2) - datetime.date(1, 1, 1)

event_config = {'description': '', 'categories': '', 'language': ''}


def load_config():
    result = dict()
    with open('config.yml', 'r', encoding='utf-8') as f:
        result = yaml.load(f)
    return result


def write_calendar(cal, filename):
    with open(filename, 'wb') as f:
        f.write(cal.to_ical())


def parse_dates(birthdays):
    for item in birthdays:
        person = item['person']
        birthday_str = person['birthday']
        if len(birthday_str) == 5:
            person['birthday_no_year'] = True
            birthday_str = birthday_str.replace(birthday_str[2], '.')
            birthday_str = birthday_str + '.0001'
        person['birthday'] = datetime.datetime.strptime(
            birthday_str, '%d.%m.%Y').date()


def display(cal):
    print(cal.to_ical().decode('utf-8'))


def sha1(string):
    if isinstance(string, str):
        string = string.encode('utf8')
    h = hashlib.sha1()
    h.update(string)
    return h.hexdigest()


def age(person, year):
    return abs(year - person['birthday'].year)


def make_event(person, year):
    event_date = person['birthday'].replace(year=year)
    description = event_config['description']

    lang_params = {'language': event_config['language']}

    if 'birthday_no_year' not in person:
        description += ', %d' % age(person, year)

    event = Event()
    event.add('uid',         sha1(person['name'] + ' birthday ' + str(year)))
    event.add('summary',     person['name'],
              encode=True, parameters=lang_params)
    event.add('description', description, encode=True, parameters=lang_params)
    event.add('categories',  event_config['categories'])
    event.add('transp',      'TRANSPARENT')
    event.add('dtstamp',     datetime.datetime(
        event_date.year, event_date.month, event_date.day))
    event.add('dtstart',     event_date)
    event.add('duration',    one_day)
    return event


def add_events(cal, birthdays, year):
    for item in birthdays:
        event = make_event(item['person'], year)
        cal.add_component(event)


def make_calendar(calname, timezone, birthdays, scale):
    cal = Calendar()
    cal.add('version',  '2.0')
    cal.add('prodid',   '-//birthdays calendar generator//b4tman.ru//')
    cal.add('calscale', 'GREGORIAN')
    cal.add('method',   'PUBLISH')
    cal.add('x-wr-timezone', timezone)
    cal.add('x-wr-calname',  calname)
    for year in range(scale['start'], scale['start'] + scale['length']):
        add_events(cal, birthdays, year)
    return cal


config = load_config()
birthdays = config['birthdays']

event_config['language'] = config['language']
event_config['description'] = config['events']['description']
event_config['categories'] = config['events']['categories']

parse_dates(birthdays)
birthdays.sort(key=lambda x: x['person']['birthday'].strftime('%m.%d'))

cal = make_calendar(config['calname'],
                    config['timezone'], birthdays, config['scale'])

if len(sys.argv) > 1:
    filename = sys.argv[1]
    write_calendar(cal, filename)
else:
    display(cal)