"""
Commande Django pour initialiser la base de données avec les 112 membres fondateurs de COOP-CA AMIFOND
"""

import json
import os
from decimal import Decimal
from datetime import datetime
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from django.db import transaction
from django.utils.dateparse import parse_date
from apps.shares.models import ShareType, ShareSubscription, SharePayment
from apps.members.models import Member
from apps.customers.models import Customer
from apps.banking.models import Account, Transaction, TransactionCategory

User = get_user_model()


class Command(BaseCommand):
    help = "Initialise la base de données avec les 112 membres fondateurs de COOP-CA AMIFOND"

    def add_arguments(self, parser):
        parser.add_argument(
            "--file",
            type=str,
            default="apps/shares/management/commands/fondateurs.json",
            help="Chemin vers le fichier JSON des fondateurs",
        )
        parser.add_argument(
            "--dry-run",
            action="store_true",
            help="Simulation sans modification de la base de données",
        )
        parser.add_argument(
            "--force",
            action="store_true",
            help="Force la création même si des données existent déjà",
        )

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

        self.stdout.write(
            self.style.SUCCESS(
                "🚀 INITIALISATION DES MEMBRES FONDATEURS COOP-CA AMIFOND"
            )
        )
        self.stdout.write("=" * 70)

        if self.dry_run:
            self.stdout.write(
                self.style.WARNING(
                    "⚠️  MODE SIMULATION - Aucune modification ne sera effectuée"
                )
            )

        try:
            # Charger les données des fondateurs
            data = self.load_founders_data(options["file"])

            # Vérifier les prérequis
            if not self.check_prerequisites():
                return

            # Créer les types de parts
            share_class = self.create_share_class(data["share_classes"][0])

            # Créer les comptes systèmes nécessaires
            share_capital_account = self.ensure_share_capital_account()

            # Traitement des membres fondateurs
            self.process_founding_members(
                data["founding_members"], share_class, share_capital_account
            )

            # Affichage du résumé final
            self.display_summary(data["metadata"])

        except Exception as e:
            self.stdout.write(
                self.style.ERROR(f"❌ Erreur lors de l'initialisation: {e}")
            )
            raise

    def load_founders_data(self, file_path):
        """Charge les données des fondateurs depuis le fichier JSON"""
        self.stdout.write(f"📁 Chargement des données depuis {file_path}...")

        if not os.path.exists(file_path):
            raise FileNotFoundError(f"Le fichier {file_path} n'existe pas")

        with open(file_path, "r", encoding="utf-8") as f:
            data = json.load(f)

        self.stdout.write(
            f"✅ {data['metadata']['nombre_membres']} membres fondateurs chargés"
        )
        return data

    def check_prerequisites(self):
        """Vérifie que les prérequis sont en place"""
        self.stdout.write("🔍 Vérification des prérequis...")

        # Vérifier qu'un superutilisateur existe
        admin_user = User.objects.filter(is_superuser=True, is_active=True).first()
        if not admin_user:
            self.stdout.write(
                self.style.ERROR(
                    "❌ Aucun superutilisateur trouvé. Créez-en un d'abord."
                )
            )
            return False

        self.admin_user = admin_user
        self.stdout.write(f"✅ Superutilisateur trouvé: {admin_user.email}")

        # Vérifier s'il existe déjà des membres fondateurs
        existing_members = Member.objects.count()
        if existing_members > 0 and not self.force:
            self.stdout.write(
                self.style.WARNING(
                    f"⚠️  {existing_members} membres existent déjà. "
                    "Utilisez --force pour continuer."
                )
            )
            return False

        return True

    def create_share_class(self, share_class_data):
        """Crée le type de parts sociales fondateurs"""
        self.stdout.write("📊 Création du type de parts sociales fondateurs...")

        if self.dry_run:
            self.stdout.write(
                f"[DRY RUN] Créerait ShareType: {share_class_data['name']}"
            )
            return None

        share_class, created = ShareType.objects.get_or_create(
            name=share_class_data["name"],
            defaults={
                "nominal_value": Decimal(share_class_data["nominal_value"]),
                "created_by": self.admin_user,
            },
        )

        action = "créé" if created else "trouvé"
        self.stdout.write(
            f"✅ Type de parts '{share_class.name}' {action} "
            f"(Valeur: {share_class.nominal_value} FCFA)"
        )

        return share_class

    def ensure_share_capital_account(self):
        """S'assure qu'un compte de capital social existe"""
        self.stdout.write("🏛️  Vérification du compte de capital social...")

        if self.dry_run:
            self.stdout.write("[DRY RUN] Vérifierait le compte SHARE_CAPITAL")
            return None

        share_capital_account = Account.objects.filter(
            type=Account.AccountType.SHARE_CAPITAL
        ).first()

        if not share_capital_account:
            share_capital_account = Account.objects.create(
                owner=self.admin_user,
                name="Capital Social COOP-CA AMIFOND",
                type=Account.AccountType.SHARE_CAPITAL,
                balance=0.00,
                created_by=self.admin_user,
            )
            self.stdout.write("✅ Compte de capital social créé")
        else:
            self.stdout.write(
                f"✅ Compte de capital social trouvé: {share_capital_account.name}"
            )

        return share_capital_account

    def process_founding_members(
        self, members_data, share_class, share_capital_account
    ):
        """Traite tous les membres fondateurs"""
        total_members = len(members_data)
        self.stdout.write(f"👥 Traitement de {total_members} membres fondateurs...")

        created_count = 0
        subscription_count = 0
        payment_count = 0
        total_subscribed_amount = Decimal("0.00")
        total_paid_amount = Decimal("0.00")

        for i, member_data in enumerate(members_data, 1):
            try:
                if self.dry_run:
                    self.stdout.write(
                        f"[DRY RUN] {i:3d}/{total_members} - "
                        f"{member_data.get('nom_complet', 'N/A')}"
                    )
                    continue

                with transaction.atomic():
                    # Créer l'utilisateur, client et membre
                    member = self.create_complete_member(member_data)
                    if member:
                        created_count += 1

                        # Créer la souscription
                        subscription = self.create_subscription(
                            member, member_data, share_class
                        )
                        if subscription:
                            subscription_count += 1
                            subscription_amount = (
                                subscription.subscribed_quantity
                                * share_class.nominal_value
                            )
                            total_subscribed_amount += subscription_amount

                            # Créer les paiements si des parts sont libérées
                            if member_data.get("parts_liberees", 0) > 0:
                                payment_created = self.create_payments(
                                    subscription,
                                    member_data,
                                    member,
                                    share_capital_account,
                                )
                                if payment_created:
                                    payment_count += 1
                                    payment_amount = (
                                        member_data["parts_liberees"]
                                        * share_class.nominal_value
                                    )
                                    total_paid_amount += payment_amount

                        # Afficher le progrès
                        if i % 10 == 0 or i == total_members:
                            self.stdout.write(
                                f"📊 Progrès: {i}/{total_members} membres traités"
                            )

            except Exception as e:
                self.stdout.write(
                    self.style.ERROR(
                        f"❌ Erreur pour le membre {member_data.get('nom_complet', 'N/A')}: {e}"
                    )
                )
                continue

        # Résumé du traitement
        self.stdout.write("\n" + "=" * 50)
        self.stdout.write("📊 RÉSUMÉ DU TRAITEMENT")
        self.stdout.write(f"✅ Membres créés: {created_count}")
        self.stdout.write(f"✅ Souscriptions créées: {subscription_count}")
        self.stdout.write(f"✅ Paiements traités: {payment_count}")
        self.stdout.write(
            f"💰 Montant total souscrit: {total_subscribed_amount:,.2f} FCFA"
        )
        self.stdout.write(f"💳 Montant total libéré: {total_paid_amount:,.2f} FCFA")

        if total_subscribed_amount > 0:
            liberation_rate = (total_paid_amount / total_subscribed_amount) * 100
            self.stdout.write(f"📈 Taux de libération: {liberation_rate:.1f}%")

    def create_complete_member(self, member_data):
        """Crée un membre complet (User + Customer + Member)"""
        try:
            # Générer email et username uniques
            base_email = self.generate_email(member_data)
            username = self.generate_username(member_data)

            # Vérifier si l'utilisateur existe déjà
            if User.objects.filter(email=base_email).exists():
                if not self.force:
                    return None

            # Créer l'utilisateur
            user = User.objects.create_user(
                email=base_email,
                username=username,
                first_name=member_data.get("prenom", ""),
                last_name=member_data.get("nom", ""),
                password="temporary123!",  # Mot de passe temporaire
            )

            # Créer le customer
            customer = Customer.objects.create(
                user=user,
                address=member_data.get("adresse", ""),
                phone_number=member_data.get("telephone", ""),
                id_card_number=member_data.get("cni", ""),
                birth_date=None,  # Non disponible dans les données
                created_by=self.admin_user,
            )

            # Convertir en membre
            member = customer.promote_to_member(
                by_user=self.admin_user,
                membership_start_date=parse_date(
                    member_data.get("date_adhesion", "2024-07-03")
                ),
            )

            # Mettre à jour les informations spécifiques
            member.role_in_cooperative = member_data.get("fonction", "Membre")
            member.membership_fee_paid = Decimal(
                str(member_data.get("frais_adhesion", "10000.00"))
            )
            member.save()

            return member

        except Exception as e:
            self.stdout.write(
                self.style.ERROR(
                    f"Erreur création membre {member_data.get('nom_complet')}: {e}"
                )
            )
            return None

    def create_subscription(self, member, member_data, share_class):
        """Crée la souscription de parts pour un membre"""
        try:
            parts_souscrites = member_data.get("parts_souscrites", 0)
            if parts_souscrites <= 0:
                return None

            subscription = ShareSubscription.objects.create(
                member=member,
                share_type=share_class,
                subscribed_quantity=parts_souscrites,
                created_by=self.admin_user,
            )

            return subscription

        except Exception as e:
            self.stdout.write(self.style.ERROR(f"Erreur création souscription: {e}"))
            return None

    def create_payments(self, subscription, member_data, member, share_capital_account):
        """Crée les paiements pour les parts libérées"""
        try:
            parts_liberees = member_data.get("parts_liberees", 0)
            if parts_liberees <= 0:
                return False

            # Créer un compte courant pour le membre s'il n'existe pas
            member_account = self.ensure_member_account(member)
            if not member_account:
                return False

            # Calculer le montant du paiement
            payment_amount = parts_liberees * subscription.share_type.nominal_value

            # S'assurer que le compte membre a suffisamment de fonds
            if member_account.balance < payment_amount:
                # Créditer le compte membre pour permettre le paiement
                member_account.balance = payment_amount
                member_account.save()

            # Effectuer le paiement via la méthode make_payment
            subscription.make_payment(
                quantity=parts_liberees,
                by_user=self.admin_user,
                from_account=member_account,
            )

            return True

        except Exception as e:
            self.stdout.write(self.style.ERROR(f"Erreur création paiement: {e}"))
            return False

    def ensure_member_account(self, member):
        """S'assure qu'un membre a un compte courant"""
        try:
            account = Account.objects.filter(
                owner=member.user, type=Account.AccountType.CURRENT
            ).first()

            if not account:
                account = Account.objects.create(
                    owner=member.user,
                    name=f"Compte Courant - {member.user.get_full_name()}",
                    type=Account.AccountType.CURRENT,
                    balance=0.00,
                    created_by=self.admin_user,
                )

            return account

        except Exception as e:
            self.stdout.write(self.style.ERROR(f"Erreur création compte membre: {e}"))
            return None

    def generate_email(self, member_data):
        """Génère un email unique pour un membre"""
        # Nettoyer le nom pour l'email
        nom_complet = member_data.get("nom_complet", "").lower()
        nom_complet = (
            nom_complet.replace(" ", ".").replace("épse", "").replace("épouse", "")
        )

        # Simplifier les caractères spéciaux
        replacements = {
            "é": "e",
            "è": "e",
            "ê": "e",
            "ë": "e",
            "à": "a",
            "â": "a",
            "ä": "a",
            "ô": "o",
            "ö": "o",
            "ù": "u",
            "û": "u",
            "ü": "u",
            "ç": "c",
            "ï": "i",
            "î": "i",
        }

        for old, new in replacements.items():
            nom_complet = nom_complet.replace(old, new)

        # Garder seulement les caractères alphanumériques et points
        email_base = "".join(c for c in nom_complet if c.isalnum() or c == ".")
        email_base = email_base.strip(".")

        if not email_base:
            email_base = f"membre{member_data.get('ordre_fondation', '000')}"

        return f"{email_base}@coopca-amifond.com"

    def generate_username(self, member_data):
        """Génère un nom d'utilisateur unique"""
        ordre = member_data.get("ordre_fondation", 0)
        nom = member_data.get("nom", "").lower()

        # Nettoyer le nom
        nom_clean = "".join(c for c in nom if c.isalnum())[:8]

        base_username = f"membre{ordre:03d}_{nom_clean}"

        # Vérifier l'unicité et ajouter un suffixe si nécessaire
        username = base_username
        counter = 1
        while User.objects.filter(username=username).exists():
            username = f"{base_username}_{counter}"
            counter += 1

        return username

    def display_summary(self, metadata):
        """Affiche le résumé final"""
        self.stdout.write("\n" + "🎉 INITIALISATION TERMINÉE")
        self.stdout.write("=" * 70)
        self.stdout.write(
            f"📊 Capital social total attendu: {metadata['capital_social_total']} FCFA"
        )
        self.stdout.write(
            f"📈 Parts souscrites attendues: {metadata['total_parts_souscrites']}"
        )
        self.stdout.write(
            f"💳 Parts libérées attendues: {metadata['total_parts_liberees']}"
        )
        self.stdout.write(
            f"📊 Taux de libération attendu: {metadata['taux_liberation']}%"
        )

        if not self.dry_run:
            # Vérifier les résultats réels
            actual_members = Member.objects.count()
            actual_subscriptions = ShareSubscription.objects.count()
            actual_payments = SharePayment.objects.count()

            self.stdout.write("\n📊 RÉSULTATS RÉELS:")
            self.stdout.write(f"👥 Membres créés: {actual_members}")
            self.stdout.write(f"📄 Souscriptions créées: {actual_subscriptions}")
            self.stdout.write(f"💳 Paiements créés: {actual_payments}")

            # Solde du compte capital social
            share_capital = Account.objects.filter(
                type=Account.AccountType.SHARE_CAPITAL
            ).first()

            if share_capital:
                self.stdout.write(
                    f"💰 Solde capital social: {share_capital.balance:,.2f} FCFA"
                )

        self.stdout.write(
            "\n✅ Initialisation des membres fondateurs terminée avec succès!"
        )
