#!/usr/bin/env python3
"""
Management command to synchronize existing Verpachtungen with LandAbrechnungen.

This command will:
1. Find all existing Verpachtungen (both legacy and new LandVerpachtung)
2. Calculate the financial impact for each year they're active
3. Update or create corresponding LandAbrechnung records
4. Provide a summary of changes made

Usage:
    python manage.py sync_abrechnungen [--dry-run] [--year YEAR]
"""

from datetime import date
from decimal import Decimal

from django.core.management.base import BaseCommand, CommandError
from django.db import transaction

from stiftung.models import LandAbrechnung, LandVerpachtung, Verpachtung


class Command(BaseCommand):
    help = "Synchronize existing Verpachtungen with LandAbrechnungen"

    def add_arguments(self, parser):
        parser.add_argument(
            "--dry-run",
            action="store_true",
            help="Show what would be done without making changes",
        )
        parser.add_argument(
            "--year",
            type=int,
            help="Only sync data for specific year",
        )
        parser.add_argument(
            "--force",
            action="store_true",
            help="Force update even if Abrechnungen already exist",
        )

    def handle(self, *args, **options):
        dry_run = options["dry_run"]
        target_year = options["year"]
        force = options["force"]

        self.stdout.write(
            self.style.SUCCESS("🔄 Starting Abrechnung synchronization...")
        )

        if dry_run:
            self.stdout.write(
                self.style.WARNING("📋 DRY RUN MODE - No changes will be made")
            )

        # Statistics
        stats = {
            "legacy_contracts": 0,
            "new_contracts": 0,
            "abrechnungen_created": 0,
            "abrechnungen_updated": 0,
            "total_rent_amount": Decimal("0.00"),
            "years_processed": set(),
        }

        try:
            with transaction.atomic():
                # Process Legacy Verpachtungen
                self.stdout.write("\n📄 Processing Legacy Verpachtungen...")
                legacy_verpachtungen = Verpachtung.objects.all()

                for verpachtung in legacy_verpachtungen:
                    stats["legacy_contracts"] += 1
                    years_affected = self._get_affected_years(
                        verpachtung.pachtbeginn,
                        verpachtung.verlaengerung or verpachtung.pachtende,
                        target_year,
                    )

                    for year in years_affected:
                        stats["years_processed"].add(year)
                        rent_amount = self._calculate_legacy_rent_for_year(
                            verpachtung, year
                        )

                        if not dry_run:
                            created, updated = self._update_abrechnung(
                                verpachtung.land,
                                year,
                                rent_amount,
                                Decimal("0.00"),  # No umlage for legacy
                                f"Legacy-Verpachtung {verpachtung.vertragsnummer}",
                                force,
                            )
                            if created:
                                stats["abrechnungen_created"] += 1
                            if updated:
                                stats["abrechnungen_updated"] += 1

                        stats["total_rent_amount"] += rent_amount

                        self.stdout.write(
                            f"  📊 {verpachtung.vertragsnummer} ({year}): {rent_amount:.2f}€"
                        )

                # Process New LandVerpachtungen
                self.stdout.write("\n🆕 Processing New LandVerpachtungen...")
                land_verpachtungen = LandVerpachtung.objects.all()

                for verpachtung in land_verpachtungen:
                    stats["new_contracts"] += 1
                    years_affected = self._get_affected_years(
                        verpachtung.pachtbeginn, verpachtung.pachtende, target_year
                    )

                    for year in years_affected:
                        stats["years_processed"].add(year)
                        rent_amount = self._calculate_new_rent_for_year(
                            verpachtung, year
                        )
                        umlage_amount = Decimal("0.00")  # To be calculated later

                        if not dry_run:
                            created, updated = self._update_abrechnung(
                                verpachtung.land,
                                year,
                                rent_amount,
                                umlage_amount,
                                f"LandVerpachtung {verpachtung.vertragsnummer}",
                                force,
                            )
                            if created:
                                stats["abrechnungen_created"] += 1
                            if updated:
                                stats["abrechnungen_updated"] += 1

                        stats["total_rent_amount"] += rent_amount

                        self.stdout.write(
                            f"  📊 {verpachtung.vertragsnummer} ({year}): {rent_amount:.2f}€"
                        )

                if dry_run:
                    # Rollback transaction in dry run
                    transaction.set_rollback(True)

        except Exception as e:
            self.stdout.write(
                self.style.ERROR(f"❌ Error during synchronization: {str(e)}")
            )
            raise CommandError(f"Synchronization failed: {str(e)}")

        # Print summary
        self.stdout.write("\n" + "=" * 50)
        self.stdout.write(self.style.SUCCESS("📈 SYNCHRONIZATION SUMMARY"))
        self.stdout.write("=" * 50)
        self.stdout.write(f"Legacy contracts processed: {stats['legacy_contracts']}")
        self.stdout.write(f"New contracts processed: {stats['new_contracts']}")
        self.stdout.write(
            f"Years affected: {', '.join(map(str, sorted(stats['years_processed'])))}"
        )
        self.stdout.write(f"Abrechnungen created: {stats['abrechnungen_created']}")
        self.stdout.write(f"Abrechnungen updated: {stats['abrechnungen_updated']}")
        self.stdout.write(f"Total rent amount: {stats['total_rent_amount']:.2f}€")

        if dry_run:
            self.stdout.write(
                self.style.WARNING("\n📋 This was a DRY RUN - no changes were saved")
            )
        else:
            self.stdout.write(
                self.style.SUCCESS("\n✅ Synchronization completed successfully!")
            )

    def _get_affected_years(self, start_date, end_date, target_year=None):
        """Get all years affected by a contract"""
        if not start_date:
            return []

        years = []
        start_year = start_date.year
        end_year = end_date.year if end_date else date.today().year

        if target_year:
            if start_year <= target_year <= end_year:
                return [target_year]
            else:
                return []

        for year in range(start_year, end_year + 1):
            years.append(year)

        return years

    def _calculate_legacy_rent_for_year(self, verpachtung, year):
        """Calculate rent for legacy Verpachtung for specific year"""
        if not verpachtung.pachtzins_jaehrlich or not verpachtung.pachtbeginn:
            return Decimal("0.00")

        year_start = date(year, 1, 1)
        year_end = date(year, 12, 31)

        contract_end_date = (
            verpachtung.verlaengerung
            if verpachtung.verlaengerung
            else verpachtung.pachtende
        )
        contract_start = max(verpachtung.pachtbeginn, year_start)
        contract_end = min(contract_end_date or year_end, year_end)

        if contract_start > contract_end:
            return Decimal("0.00")

        days_in_year = (year_end - year_start).days + 1
        days_active = (contract_end - contract_start).days + 1
        proportion = Decimal(str(days_active)) / Decimal(str(days_in_year))

        return Decimal(str(verpachtung.pachtzins_jaehrlich)) * proportion

    def _calculate_new_rent_for_year(self, verpachtung, year):
        """Calculate rent for new LandVerpachtung for specific year"""
        if not verpachtung.pachtzins_pauschal or not verpachtung.pachtbeginn:
            return Decimal("0.00")

        year_start = date(year, 1, 1)
        year_end = date(year, 12, 31)

        contract_start = max(verpachtung.pachtbeginn, year_start)
        contract_end = min(verpachtung.pachtende or year_end, year_end)

        if contract_start > contract_end:
            return Decimal("0.00")

        days_in_year = (year_end - year_start).days + 1
        days_active = (contract_end - contract_start).days + 1
        proportion = Decimal(str(days_active)) / Decimal(str(days_in_year))

        return Decimal(str(verpachtung.pachtzins_pauschal)) * proportion

    def _update_abrechnung(
        self, land, year, rent_amount, umlage_amount, source_note, force
    ):
        """Update or create Abrechnung for specific land and year"""
        abrechnung, created = LandAbrechnung.objects.get_or_create(
            land=land,
            abrechnungsjahr=year,
            defaults={
                "pacht_vereinnahmt": rent_amount,
                "umlagen_vereinnahmt": umlage_amount,
                "bemerkungen": f'[{date.today().strftime("%d.%m.%Y")}] Automatisch synchronisiert von {source_note}',
            },
        )

        updated = False
        if not created and force:
            # Update existing
            abrechnung.pacht_vereinnahmt += rent_amount
            abrechnung.umlagen_vereinnahmt += umlage_amount

            sync_note = f'[{date.today().strftime("%d.%m.%Y")}] Resync: +{rent_amount:.2f}€ von {source_note}'
            if abrechnung.bemerkungen:
                abrechnung.bemerkungen += f"\n{sync_note}"
            else:
                abrechnung.bemerkungen = sync_note

            abrechnung.save()
            updated = True

        return created, updated
