from django.core.management.base import BaseCommand
from django.conf import settings
from django.db import transaction
from pathlib import Path
import json, time

from recharge.models import Operator, Circle
from recharge.services.provider_factory import get_recharge_client

def safe_str(x): 
    return str(x).strip() if x is not None else ""

class Command(BaseCommand):
    help = "Fetch and cache all recharge plans (operator x circle) to local JSON files."

    def add_arguments(self, parser):
        parser.add_argument("--service", default="Mobile", help="Service type (default: Mobile)")
        parser.add_argument("--provider", default=None, help="Override settings.RECHARGE_PROVIDER")
        parser.add_argument("--limit", type=int, default=None, help="Limit number of requests (debug)")
        parser.add_argument("--sleep", type=float, default=0.3, help="Sleep seconds between requests to be polite")
        parser.add_argument("--force", action="store_true", help="Force refresh even if file exists")

    def handle(self, *args, **opts):
        provider_key = (opts["provider"] or getattr(settings, "RECHARGE_PROVIDER", "goterpay")).lower()
        source_value = settings.PROVIDER_SOURCE_MAP.get(provider_key, provider_key)
        service_type = opts["service"]
        limit = opts["limit"]
        delay = float(opts["sleep"])
        force = bool(opts["force"])

        cache_root = Path(getattr(settings, "PLANS_CACHE_DIR", Path("."))) / provider_key
        cache_root.mkdir(parents=True, exist_ok=True)

        self.stdout.write(self.style.NOTICE(
            f"Provider={provider_key} | DB source='{source_value}' | service='{service_type}' | cache='{cache_root}'"
        ))

        # Pull operators/circles for this provider
        # operators = Operator.objects.filter(service_type__iexact=service_type, source__iexact=source_value)
        operators = Operator.objects.filter(service_type__icontains=service_type, source__iexact=source_value)
        circles = Circle.objects.filter(source__iexact=source_value)

        total_pairs = len(operators) * len(circles)
        self.stdout.write(f"Found {len(operators)} operators x {len(circles)} circles = {total_pairs} combinations")

        client = get_recharge_client()

        done = 0
        ok = 0
        skipped = 0
        failed = 0
        errors = []
        exit
        for op in operators:
            op_code = safe_str(op.code)
            for c in circles:
                circle_code = safe_str(c.code)
                fname = f"{op_code}_{circle_code}.json"
                fpath = cache_root / fname

                if fpath.exists() and not force:
                    skipped += 1
                    done += 1
                    if limit and done >= limit:
                        break
                    continue

                try:
                    resp = client.recharge_plan(op_code, circle_code)
                    plans = resp.get("Data") or resp.get("data") or []
                    payload = {
                        "provider": provider_key,
                        "source": source_value,
                        "service_type": service_type,
                        "operator_code": op_code,
                        "operator_name": op.name,
                        "circle_code": circle_code,
                        "circle_name": c.name,
                        "count": len(plans),
                        "raw": plans,   # raw list from provider
                    }
                    with open(fpath, "w", encoding="utf-8") as f:
                        json.dump(payload, f, ensure_ascii=False, indent=2)
                    ok += 1
                except Exception as e:
                    failed += 1
                    errors.append(f"{op_code}-{circle_code}: {e}")
                finally:
                    done += 1
                    if delay:
                        time.sleep(delay)
                    if limit and done >= limit:
                        break
            if limit and done >= limit:
                break

        self.stdout.write(self.style.SUCCESS(
            f"Finished: ok={ok}, skipped={skipped}, failed={failed}, attempted={done}"
        ))
        if errors:
            self.stdout.write(self.style.WARNING("Errors:"))
            for line in errors[:20]:
                self.stdout.write(f" - {line}")
            if len(errors) > 20:
                self.stdout.write(f" ... and {len(errors)-20} more")
