from datetime import date
from typing import Dict, List, Tuple

from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.management import BaseCommand, CommandError
from django.db import transaction

from gaehsnitz.models import Drink, Consumption, Donation, Payment, Payback

User = get_user_model()


def user(name: str):
    obj, _ = User.objects.get_or_create(username=name)
    return obj


def donation(user, day, month, amount, note):
    return Donation.objects.create(
        from_user=user,
        date=date(2022, month, day),
        amount=amount,
        note=note,
    )


def payment(purpose, day, month, amount, user):
    return Payment.objects.create(
        from_user=user,
        date=date(2022, month, day),
        amount=amount,
        purpose=purpose,
    )


def payback(user, day, month, amount, note):
    return Payback.objects.create(
        to_user=user,
        date=date(2022, month, day),
        amount=amount,
        note=note,
    )


def consumption(day: int, for_free: bool, drink_dict: Dict[User, List[Tuple[int, Drink]]]):
    for user, drink_list in drink_dict.items():
        for amount, drink in drink_list:
            Consumption.objects.create(user=user, drink=drink, amount=amount, day=day, for_free=for_free)


class Command(BaseCommand):
    @transaction.atomic()
    def handle(self, *args, **options):
        if any(model.objects.exists() for model in [Donation, Payment, Drink, Consumption]):
            raise CommandError("clear all donation, payment, drink and consumption objects before running this command")

        # --------------- PEOPLE ---------------

        aimee = user("aimee")
        andrew = user("andrew")
        annemarie = user("annemarie")
        cathi_clemens = user("cathi_clemens")
        domi = user("domi")
        fiddi_melli = user("fiddi_melli")
        flo = user("flo")
        hans_welle = user("hans_welle")
        herald = user("herald")
        josi = user("josi")
        kevin = user("kevin")
        lasse = user("lasse")
        lilly_simon = user("lilly_simon")
        lutz = user("lutz")
        melokomplott = user("melokomplott")
        peter = user("peter")
        rebecca = user("rebecca")
        residudes = user("residudes")
        resi_simon = user("resi_simon")
        robert = user("robert")
        robin = user("robin")
        sandro_related = user("sandro_related")
        seth_family = user("seth_family")
        suse = user("suse")
        thure = user("thure")
        tobi = user("tobi")

        anonymous_spender = user("anonymous_spender")
        anonymous_payer = user("anonymous_payer")

        # --------------- DONATIONS ---------------

        # via paypal
        donation(herald, 22, 4, 50, "PayPal")
        donation(josi, 29, 4, 30, "PayPal")
        donation(robert, 9, 5, 15, "PayPal")
        donation(domi, 21, 8, 30, "PayPal")
        donation(cathi_clemens, 24, 8, 70, "PayPal")
        donation(robert, 24, 8, 50, "PayPal")
        donation(lilly_simon, 26, 8, 60, "PayPal")

        # via bank
        donation(aimee, 28, 6, 50, "Überweisung")
        donation(suse, 26, 8, 60, "Überweisung")

        # on the list
        donation(annemarie, 26, 8, 25, "Kasse")
        donation(peter, 26, 8, 25, "Kasse")
        donation(fiddi_melli, 27, 8, 40, "Kasse")
        donation(resi_simon, 27, 8, 20, "Kasse")
        donation(sandro_related, 27, 8, 40, "Kasse")
        donation(seth_family, 27, 8, 30, "Kasse")

        # unknown donations
        money_in_register = 194.50
        direct_band_payments = 110
        donation_sum_on_the_list = 180
        remaining = money_in_register + direct_band_payments - donation_sum_on_the_list
        donation(anonymous_spender, 28, 8, remaining, "übrig in Kasse")

        # hinterher
        donation(seth_family, 30, 8, 30, "persönlich")
        donation(lutz, 30, 8, 80, "PayPal")
        donation(kevin, 8, 9, 15, "Paypal")
        donation(robert, 9, 9, 33, "Paypal")
        donation(kevin, 9, 9, 35, "Paypal")

        # --------------- PAYMENTS ---------------

        payment("Baumarkt/Elektrik", 16, 7, 70, flo)
        payment("Baumarkt/Elektrik", 18, 7, 27, flo)
        payment("Dixis", 8, 8, 328, josi)
        payment("Getränke/Anzahlung", 22, 8, 400, fiddi_melli)
        payment("Supermarkt/Essen", 25, 8, 193, herald)
        payment("Band/Direct Juice", 27, 8, 50, anonymous_payer)
        payment("Band/Melokomplott", 27, 8, 60, anonymous_payer)
        payment("Getränke/Abrechnung", 1, 9, 122, fiddi_melli)

        # --------------- PAYBACKS ---------------

        # directly from the register
        payback(flo, 28, 8, money_in_register, "Kasse")

        # --------------- DRINKS ---------------

        sterni = Drink.objects.create(
            name="Sterni",
            crates_ordered=30,
            crates_purchased=15,
            crates_returned=10,
            purchase_price_per_crate=8.49,
            deposit_per_crate=3.10,
            bottles_per_crate=20,
            bottle_size=0.5,
            sale_price_per_bottle=1.50,
        )
        krosti = Drink.objects.create(
            name="Krosti",
            crates_ordered=20,
            crates_purchased=9,
            crates_returned=5,
            purchase_price_per_crate=13.49,
            deposit_per_crate=3.10,
            bottles_per_crate=20,
            bottle_size=0.5,
            sale_price_per_bottle=2.00,
        )
        radler = Drink.objects.create(
            name="Radler",
            crates_ordered=8,
            crates_purchased=5,
            crates_returned=3,
            purchase_price_per_crate=16.49,
            deposit_per_crate=3.10,
            bottles_per_crate=20,
            bottle_size=0.5,
            sale_price_per_bottle=2.00,
        )
        wasser = Drink.objects.create(
            name="Wasser",
            crates_ordered=15,
            crates_purchased=6,
            crates_returned=4,
            purchase_price_per_crate=5.99,
            deposit_per_crate=3.30,
            bottles_per_crate=12,
            bottle_size=1.0,
            sale_price_per_bottle=1.00,
        )
        mate = Drink.objects.create(
            name="Mate",
            crates_ordered=5,
            crates_purchased=3,
            crates_returned=2,
            purchase_price_per_crate=13.99,
            deposit_per_crate=4.50,
            bottles_per_crate=20,
            bottle_size=0.5,
            sale_price_per_bottle=2.00,
        )
        cola = Drink.objects.create(
            name="Vita Cola / Pepsi",
            crates_ordered=4,
            crates_purchased=3,
            crates_returned=2,
            purchase_price_per_crate=10.24,  # equally 9.49 and 10.99
            deposit_per_crate=3.30,
            bottles_per_crate=12,
            bottle_size=1.0,
            sale_price_per_bottle=2.00,
        )
        wein = Drink.objects.create(
            name="Wein (Glas)",
            crates_ordered=0,
            crates_purchased=6,
            crates_returned=0,
            purchase_price_per_crate=0,
            deposit_per_crate=0,
            bottles_per_crate=3,
            bottle_size=0.25,
            sale_price_per_bottle=1.50,
        )

        # --------------- THURSDAY ---------------

        consumption(
            day=1,
            for_free=False,
            drink_dict={
                robert: [(2, mate), (2, radler), (1, wasser)],
                thure: [(4, sterni), (1, krosti), (2, radler)],
                tobi: [(7, sterni), (2, krosti)],
                herald: [(1, radler), (2, wasser), (4, wein)],
                annemarie: [(1, sterni), (1, wasser), (2, wein)],
                cathi_clemens: [(1, sterni), (2, radler)],
                flo: [(6, sterni), (1, wasser)],
                josi: [(4, sterni)],
                aimee: [(5, sterni)],
                lutz: [(1, sterni), (1, wasser)],
                lasse: [(2, sterni), (1, wasser)],
                domi: [(1, sterni), (1, radler)],
            },
        )
        consumption(
            day=1,
            for_free=True,
            drink_dict={
                seth_family: [(1, krosti), (1, radler)],
            },
        )

        # --------------- FRIDAY ---------------

        consumption(
            day=2,
            for_free=False,
            drink_dict={
                robert: [(2, mate), (1, radler)],
                thure: [(8, sterni), (2, krosti), (1, wasser)],
                tobi: [(2, mate), (5, sterni), (5, krosti), (3, radler), (1, cola)],
                herald: [(1, mate), (1, sterni), (2, radler), (1, cola), (4, wasser), (7, wein)],
                annemarie: [(2, mate), (9, sterni), (1, krosti), (2, radler), (3, wasser)],
                cathi_clemens: [(3, sterni), (3, radler)],
                flo: [(1, mate), (6, sterni), (3, wasser)],
                josi: [(8, sterni), (1, krosti), (2, radler)],
                andrew: [(4, sterni)],
                peter: [(7, sterni), (1, krosti), (2, wasser)],
                fiddi_melli: [(6, sterni), (3, radler), (1, wasser)],
                suse: [(1, krosti), (1, radler)],
                lilly_simon: [(1, mate), (7, sterni), (3, wasser)],
            },
        )

        consumption(
            day=2,
            for_free=True,
            drink_dict={
                seth_family: [(1, mate), (6, sterni), (3, wasser)],
                aimee: [(1, mate), (9, sterni), (3, wasser)],
                lutz: [(1, mate), (9, sterni), (3, wasser)],
                lasse: [(7, sterni), (1, wasser)],
                domi: [(1, mate), (4, sterni), (1, wasser)],
                hans_welle: [(3, mate), (7, sterni), (7, krosti), (1, cola), (2, wasser)],
            },
        )

        # --------------- SATURDAY ---------------

        consumption(
            day=3,
            for_free=False,
            drink_dict={
                robert: [(4, mate), (1, cola), (4, wasser)],
                tobi: [(9, sterni), (1, krosti), (2, radler), (1, cola)],
                herald: [(2, mate), (2, radler), (3, wasser), (5, wein)],
                annemarie: [(2, mate), (6, sterni), (3, radler), (1, cola), (1, wasser)],
                cathi_clemens: [(4, sterni), (8, radler), (1, wasser)],
                flo: [(2, mate), (8, sterni), (1, radler), (3, wasser)],
                josi: [(9, sterni), (2, radler), (2, wasser)],
                aimee: [(10, sterni), (2, radler)],
                lutz: [(1, krosti), (1, wasser)],
                lasse: [(1, mate), (8, sterni)],
                domi: [(6, sterni), (2, radler), (1, wasser)],
                peter: [(3, sterni), (3, krosti), (2, radler)],
                fiddi_melli: [(1, mate), (1, wasser)],
                suse: [(1, mate), (1, sterni), (2, krosti), (4, radler)],
                lilly_simon: [(1, mate), (2, radler), (7, wasser)],
                kevin: [(1, mate), (1, radler)],
                rebecca: [(1, radler)],
                resi_simon: [(8, sterni), (1, radler), (1, wasser)],
            },
        )

        consumption(
            day=3,
            for_free=True,
            drink_dict={
                thure: [(1, mate), (4, sterni), (5, radler), (3, wasser)],
                seth_family: [(1, mate), (2, sterni), (12, krosti), (1, wasser)],
                andrew: [(3, sterni), (2, krosti), (3, radler), (1, wasser)],
                robin: [(1, mate), (4, krosti), (2, radler)],
                melokomplott: [(5, mate), (13, sterni), (1, krosti), (1, radler)],
                residudes: [(2, mate), (1, sterni), (15, krosti), (7, radler), (1, wasser)],
            },
        )

        # --------------- ADMIN STUFF ---------------

        if not settings.PRODUCTION:
            flo.set_password("123")
            flo.is_staff = True
            flo.is_superuser = True
            flo.save()
