#!/usr/bin/env python3
"""Méthode AD GESTION v1.0.0, exemple FICTIF. Python 3, sans dépendance.
Usage : python3 reproduire-portefeuille.py portefeuille-fictif-v1.csv
Les montants du CSV sont des centimes entiers ; le périmètre est décrit dans le TXT.
"""
import csv
import json
import sys
from decimal import Decimal, ROUND_HALF_UP

DAYS = ("managedDays", "lettableDays", "occupiedDays")
MONEY = ("openingReceivableCents", "billedRentCents", "paidCurrentCents", "paidOpeningCents", "adjustmentsCents")


def compute(filename):
    with open(filename, encoding="utf-8-sig", newline="") as stream:
        rows = list(csv.DictReader(stream, delimiter=";"))
    if len(rows) > 10000:
        raise ValueError("Trop de lignes pour ce modèle pédagogique")
    totals = dict.fromkeys(DAYS + MONEY, 0)
    seen = set()
    billed_units = lettable_units = 0
    for row in rows:
        key = row["example"]
        if not key or key in seen:
            raise ValueError("Identifiant absent ou dupliqué")
        seen.add(key)
        values = {name: int(row[name]) for name in DAYS + MONEY}
        if not 0 <= values["occupiedDays"] <= values["lettableDays"] <= values["managedDays"] <= 365:
            raise ValueError("Jours incohérents")
        if any(abs(values[name]) > 10000000000 or (name != "adjustmentsCents" and values[name] < 0) for name in MONEY):
            raise ValueError("Montant incohérent")
        if values["paidCurrentCents"] > values["billedRentCents"] or values["paidOpeningCents"] > values["openingReceivableCents"]:
            raise ValueError("Paiement supérieur à sa cohorte ; rapprocher les avances séparément")
        closing = values["openingReceivableCents"] + values["billedRentCents"] + values["adjustmentsCents"] - values["paidCurrentCents"] - values["paidOpeningCents"]
        if closing < 0:
            raise ValueError("Solde créditeur hors périmètre")
        for name, value in values.items():
            totals[name] += value
        billed_units += values["billedRentCents"] > 0
        lettable_units += values["lettableDays"] > 0
    cash = totals["paidCurrentCents"] + totals["paidOpeningCents"]
    vacant = totals["lettableDays"] - totals["occupiedDays"]

    def percentage(numerator, denominator):
        if not denominator:
            return None
        return str((Decimal(numerator) * 100 / Decimal(denominator)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))

    return dict(totals, sampleSize=len(rows), billedUnits=billed_units, lettableUnits=lettable_units,
                excludedDays=totals["managedDays"] - totals["lettableDays"], vacantDays=vacant,
                cashReceivedCents=cash,
                closingReceivableCents=totals["openingReceivableCents"] + totals["billedRentCents"] + totals["adjustmentsCents"] - cash,
                collectionPercent=percentage(totals["paidCurrentCents"], totals["billedRentCents"]),
                vacancyPercent=percentage(vacant, totals["lettableDays"]))


if __name__ == "__main__":
    if len(sys.argv) != 2:
        raise SystemExit("Usage : python3 reproduire-portefeuille.py portefeuille-fictif-v1.csv")
    print(json.dumps(compute(sys.argv[1]), ensure_ascii=False, indent=2))
