# -*- coding: utf-8 -*-
"""Zeitbericht: Zeiterfassungs-CSV (zeitstempel;stunden;projekt) zusammenfassen."""
import cgi
import datetime
import io
import json
import os
import sys
from optparse import OptionParser
from typing import Dict, List


def kodierung_aus(content_type):
    """'text/csv; charset=latin-1' -> 'latin-1' (Standard utf-8)."""
    _, params = cgi.parse_header(content_type or "text/csv")
    return params.get("charset", "utf-8")


def lade_eintraege(pfad, kodierung="utf-8"):
    # type: (str, str) -> List[Dict]
    eintraege = []
    f = io.open(pfad, "r", encoding=kodierung)
    try:
        for zeile in f:
            zeile = zeile.strip()
            if not zeile or zeile.startswith("#"):
                continue
            ts, stunden, projekt = zeile.split(";")
            eintraege.append({"zeit": datetime.datetime.utcfromtimestamp(int(ts)),
                              "stunden": float(stunden.replace(",", ".")), "projekt": projekt.strip()})
    finally:
        f.close()
    return eintraege


def zusammenfassen(eintraege, projekt=None, ab=None):
    # type: (List[Dict], str, datetime.date) -> Dict
    auswahl = [e for e in eintraege
               if (projekt is None or e["projekt"] == projekt) and (ab is None or e["zeit"].date() >= ab)]
    je_projekt = {}  # type: Dict[str, float]
    for e in auswahl:
        je_projekt[e["projekt"]] = je_projekt.get(e["projekt"], 0.0) + e["stunden"]
    return {
        "anzahl": len(auswahl),
        "stunden": round(sum(e["stunden"] for e in auswahl), 2),
        "je_projekt": dict(sorted((k, round(v, 2)) for k, v in je_projekt.items())),
        "erster": auswahl and min(e["zeit"] for e in auswahl).isoformat() + "Z" or None,
        "letzter": auswahl and max(e["zeit"] for e in auswahl).isoformat() + "Z" or None,
    }


def als_text(z):
    zeilen = ["Eintraege: %d, Stunden: %.2f" % (z["anzahl"], z["stunden"])]
    for p, h in z["je_projekt"].items():
        zeilen.append("  %-12s %7.2f h" % (p, h))
    return "\n".join(zeilen)


def main(argv=None):
    parser = OptionParser(usage="%prog [optionen] DATEI")
    parser.add_option("-p", "--projekt", dest="projekt", help="nur dieses Projekt")
    parser.add_option("--ab", dest="ab", help="nur ab Datum JJJJ-MM-TT")
    parser.add_option("-f", "--format", dest="format", default="text", choices=["text", "json"],
                      help="text oder json")
    parser.add_option("--content-type", dest="content_type", default="text/csv; charset=utf-8",
                      help="Kodierung der Datei als Content-Type")
    optionen, args = parser.parse_args(argv)
    if len(args) != 1:
        parser.error("genau eine DATEI angeben")
    if not os.path.exists(args[0]):
        sys.stderr.write("Datei nicht gefunden: %s\n" % args[0])
        return 3
    ab = None
    if optionen.ab:
        try:
            ab = datetime.datetime.strptime(optionen.ab, "%Y-%m-%d").date()
        except ValueError:
            parser.error("--ab braucht JJJJ-MM-TT")
    z = zusammenfassen(lade_eintraege(args[0], kodierung_aus(optionen.content_type)), optionen.projekt, ab)
    if optionen.format == "json":
        print(json.dumps(z, sort_keys=True))
    else:
        print(als_text(z))
    return 0


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