"""Seed countries, states and cities master data for the whole world.

Data source: https://github.com/dr5hn/countries-states-cities-database
(json/countries+states+cities.json — a nested array of countries, each
with its states, each state with its cities).

Usage:
    python seed_world_data.py [path-to-world-json]

If no path is given, the script looks for data/world-locations.json next
to this file and downloads it from GitHub when missing (~46 MB).

The script is idempotent: existing countries/states/cities (matched by
name within their parent) are kept and only missing rows are inserted,
so it is safe to run after seed_india_data.py or on a partially seeded
database.
"""
import json
import os
import sys
import urllib.request

DATA_URL = (
    "https://raw.githubusercontent.com/dr5hn/countries-states-cities-database"
    "/master/json/countries%2Bstates%2Bcities.json"
)
DEFAULT_JSON_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "data", "world-locations.json")


def load_dataset(json_path):
    if not os.path.exists(json_path):
        print(f"Dataset not found at {json_path}, downloading (~46 MB)...")
        os.makedirs(os.path.dirname(json_path), exist_ok=True)
        urllib.request.urlretrieve(DATA_URL, json_path)
        print("Download complete.")
    with open(json_path, "r", encoding="utf-8") as f:
        return json.load(f)


def normalize_phone_code(raw):
    if not raw:
        return None
    code = str(raw).strip()
    if not code.startswith("+"):
        code = "+" + code
    return code[:15]


def seed_world(json_path):
    from apps.master_data.models import Country, State, City

    data = load_dataset(json_path)
    print(f"Loaded {len(data)} countries from dataset.")

    total_countries_created = 0
    total_states_created = 0
    total_cities_created = 0

    for entry in data:
        country_name = (entry.get("name") or "").strip()
        if not country_name:
            continue
        iso2 = entry.get("iso2")

        country, created = Country.objects.get_or_create(
            name=country_name,
            defaults={
                "iso2": iso2,
                "iso3": entry.get("iso3"),
                "phone_code": normalize_phone_code(entry.get("phonecode")),
                "region": entry.get("region"),
                "subregion": entry.get("subregion"),
                "status": 1,
            },
        )
        if created:
            total_countries_created += 1

        # States: keep existing ones (matched by name), insert the rest.
        states_cache = {s.name: s for s in State.objects.filter(country=country)}
        new_states = []
        for state_entry in entry.get("states", []):
            state_name = (state_entry.get("name") or "").strip()
            if not state_name or state_name in states_cache:
                continue
            states_cache[state_name] = None  # placeholder to dedupe within dataset
            new_states.append(State(name=state_name, country=country, country_code=iso2))
        if new_states:
            State.objects.bulk_create(new_states, batch_size=1000)
            total_states_created += len(new_states)
            states_cache = {s.name: s for s in State.objects.filter(country=country)}

        # Cities: dedupe on (name, state name) within the country.
        existing_cities = set(
            City.objects.filter(country=country).values_list("name", "state__name")
        )
        new_cities = []
        for state_entry in entry.get("states", []):
            state_name = (state_entry.get("name") or "").strip()
            state_obj = states_cache.get(state_name)
            if not state_obj:
                continue
            for city_entry in state_entry.get("cities", []):
                city_name = (city_entry.get("name") or "").strip()
                if not city_name or (city_name, state_name) in existing_cities:
                    continue
                existing_cities.add((city_name, state_name))
                new_cities.append(
                    City(name=city_name, state=state_obj, country=country, country_code=iso2)
                )
        if new_cities:
            City.objects.bulk_create(new_cities, batch_size=1000)
            total_cities_created += len(new_cities)

    print(f"Created {total_countries_created} countries, "
          f"{total_states_created} states, {total_cities_created} cities.")
    print(f"Totals now: {Country.objects.count()} countries, "
          f"{State.objects.count()} states, {City.objects.count()} cities.")


if __name__ == "__main__":
    sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.dev")
    import django

    django.setup()
    path = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_JSON_PATH
    seed_world(path)
