"""
Management command: create_default_business_cards
==================================================
Place this file at:
    expat_life/management/commands/create_default_business_cards.py

Run manually:
    python manage.py create_default_business_cards

Schedule as a daily cron job (example – runs at 2 AM):
    0 2 * * * /path/to/venv/bin/python /path/to/project/manage.py create_default_business_cards >> /var/log/bc_cron.log 2>&1
"""

import os
import logging

from django.conf import settings
from django.core.files.base import ContentFile
from django.core.management.base import BaseCommand
from django.urls import reverse

from affiliates_app.models import AffiliateProfile, AffiliateBusinessCard
from affiliates_app.utils import generate_qr_code_image, generate_business_card_composite

logger = logging.getLogger(__name__)

# The three default promotional links for newly registered affiliates
DEFAULT_PROMO_LINKS = [
    ('expat_life:home',             'Home Page'),
    ('expat_life:foreigner_signup', 'Foreigner Signup'),
    ('expat_life:package_list',     'Packages'),
]


def build_referral_url_no_request(url_name: str, affiliate_code: str) -> str:
    """
    Request-free version of affiliates_app's build_referral_url.
    Reads domain and protocol from settings instead of the request object.

    Add to settings.py:
        SITE_DOMAIN = '127.0.0.1:8000'   # dev
        SITE_DOMAIN = 'yourdomain.com'    # production
        DEFAULT_PROTOCOL = 'http'         # dev
        DEFAULT_PROTOCOL = 'https'        # production
    """
    path = reverse(url_name)
    domain = getattr(settings, 'SITE_DOMAIN', settings.ALLOWED_HOSTS[0])
    protocol = getattr(settings, 'DEFAULT_PROTOCOL', 'https')
    return f"{protocol}://{domain}{path}?ref={affiliate_code}"


class Command(BaseCommand):
    help = (
        "Create 3 default business cards (Home, Signup, Packages) for every "
        "affiliate who has no business cards yet. Safe to run as a daily cron job."
    )

    def add_arguments(self, parser):
        parser.add_argument(
            '--dry-run',
            action='store_true',
            help='Show which affiliates would be processed without writing anything.',
        )

    def handle(self, *args, **options):
        dry_run: bool = options['dry_run']

        # ------------------------------------------------------------------ #
        # 1.  Find affiliates with zero business cards                         #
        # ------------------------------------------------------------------ #
        affiliates_without_cards = AffiliateProfile.objects.filter(
            business_cards__isnull=True     # reverse FK name — adjust if yours differs
        ).select_related('user')

        total = affiliates_without_cards.count()

        if total == 0:
            self.stdout.write(self.style.SUCCESS("No new affiliates need default cards. Done."))
            return

        self.stdout.write(
            f"Found {total} affiliate(s) with no business cards. "
            f"{'[DRY RUN] ' if dry_run else ''}Processing…\n"
        )

        # ------------------------------------------------------------------ #
        # 2.  Shared assets — load once, fail fast if missing                 #
        # ------------------------------------------------------------------ #
        background_path = os.path.join(
            settings.BASE_DIR, 'static', 'expat_life', 'images', 'bc_background_with_logo.png'
        )
        name_font    = os.path.join(settings.BASE_DIR, 'static', 'fonts', 'Poppins-Medium.ttf')
        contact_font = os.path.join(settings.BASE_DIR, 'static', 'fonts', 'Poppins-Regular.ttf')
        code_font    = os.path.join(settings.BASE_DIR, 'static', 'fonts', 'Poppins-Medium.ttf')

        if not os.path.exists(background_path):
            self.stderr.write(
                self.style.ERROR(f"Background image not found: {background_path}\nAborting.")
            )
            return

        created_total = 0
        error_total   = 0

        # ------------------------------------------------------------------ #
        # 3.  Iterate affiliates                                               #
        # ------------------------------------------------------------------ #
        for affiliate in affiliates_without_cards:
            affiliate_label = f"{affiliate.user.email} (code={affiliate.affiliate_code})"

            if dry_run:
                self.stdout.write(f"  [DRY RUN] Would create 3 cards for {affiliate_label}")
                continue

            cards_created_for_affiliate = 0

            for url_name, link_label in DEFAULT_PROMO_LINKS:
                try:
                    referral_url = build_referral_url_no_request(url_name, affiliate.affiliate_code)

                    # -- QR code ------------------------------------------------
                    qr_buffer = generate_qr_code_image(referral_url, size=300)

                    # -- Business card composite --------------------------------
                    composite_buffer = generate_business_card_composite(
                        affiliate_profile=affiliate,
                        qr_image_buffer=qr_buffer,
                        background_image_path=background_path,
                        card_size=(1050, 600),
                        name_font_path=name_font,
                        contact_font_path=contact_font,
                        code_font_path=code_font,
                    )

                    # -- Persist (update_or_create is idempotent) ---------------
                    slug = url_name.split(':')[-1]  # e.g. 'home', 'foreigner_signup'

                    card, card_created = AffiliateBusinessCard.objects.update_or_create(
                        affiliate_profile=affiliate,
                        referral_link=referral_url,
                        defaults={
                            'design_version': 'default',
                            'is_active': True,
                        },
                    )

                    qr_filename   = f"qr_{affiliate.affiliate_code}_{slug}.png"
                    card_filename = f"card_{affiliate.affiliate_code}_{slug}.png"

                    if not card_created:
                        card.delete_qr_and_card_files()

                    card.qr_code_image.save(
                        qr_filename, ContentFile(qr_buffer.getvalue()), save=False
                    )
                    card.business_card_image.save(
                        card_filename, ContentFile(composite_buffer.getvalue()), save=False
                    )
                    card.save()

                    cards_created_for_affiliate += 1
                    action = "Created" if card_created else "Updated"
                    logger.info("%s card '%s' for affiliate %s", action, link_label, affiliate_label)

                except Exception as exc:
                    error_total += 1
                    logger.exception(
                        "Failed to create card '%s' for affiliate %s: %s",
                        link_label, affiliate_label, exc
                    )
                    self.stderr.write(
                        self.style.WARNING(
                            f"  ✗ {affiliate_label} — '{link_label}' failed: {exc}"
                        )
                    )

            if cards_created_for_affiliate:
                created_total += cards_created_for_affiliate
                self.stdout.write(
                    self.style.SUCCESS(
                        f"  ✓ {affiliate_label} — {cards_created_for_affiliate} card(s) created"
                    )
                )

        # ------------------------------------------------------------------ #
        # 4.  Summary                                                          #
        # ------------------------------------------------------------------ #
        self.stdout.write(
            self.style.SUCCESS(
                f"\nDone. Cards created: {created_total}  |  Errors: {error_total}"
            )
        )