"""
migrate_provisioning_data.py — Migrate WiFi and VoIP provisioning data
from GenieACS MariaDB into ERPNext Service Equipment custom fields.

Sources:
  - provisioning-data.json (exported from GenieACS MariaDB at legacy-db)
    Contains: wifi[] (1,713 entries) and voip[] (797 entries)

Matching strategy:
  - WiFi: wifi.serial (Deco MAC) → Service Equipment.mac_address
  - VoIP: voip.serial (RCMG serial) → Service Equipment.serial_number

Run inside erpnext-backend-1:
  /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/migrate_provisioning_data.py
"""
import frappe
import json
import os

os.chdir("/home/frappe/frappe-bench/sites")
frappe.init(site="erp.gigafibre.ca", sites_path=".")
frappe.connect()
frappe.local.flags.ignore_permissions = True
print("Connected:", frappe.local.site)


# ═══════════════════════════════════════════════════════════════
# Load provisioning data export
# ═══════════════════════════════════════════════════════════════
# This file should be copied to the bench directory from:
# scripts/migration/genieacs-export/provisioning-data.json
PROV_FILE = "/home/frappe/frappe-bench/provisioning-data.json"
if not os.path.exists(PROV_FILE):
    # Try the git repo path
    PROV_FILE = os.path.expanduser(
        "~/frappe-bench/apps/gigafibre-fsm/scripts/migration/genieacs-export/provisioning-data.json"
    )
if not os.path.exists(PROV_FILE):
    print("ERROR: provisioning-data.json not found. Copy it to /home/frappe/frappe-bench/")
    print("Source: scripts/migration/genieacs-export/provisioning-data.json")
    exit(1)

with open(PROV_FILE) as f:
    prov_data = json.load(f)

wifi_entries = prov_data.get("wifi", [])
voip_entries = prov_data.get("voip", [])
print("WiFi entries: {}".format(len(wifi_entries)))
print("VoIP entries: {}".format(len(voip_entries)))


# ═══════════════════════════════════════════════════════════════
# Build MAC → Equipment Name map
# ═══════════════════════════════════════════════════════════════
print("\nBuilding MAC address and serial number maps...")

# MAC address → Service Equipment name (normalized to uppercase, no colons)
mac_map = {}
rows = frappe.db.sql("""
    SELECT name, mac_address FROM "tabService Equipment"
    WHERE mac_address IS NOT NULL AND mac_address != ''
""", as_dict=True)
for r in rows:
    mac_clean = r["mac_address"].upper().replace(":", "").replace("-", "").replace(".", "")
    mac_map[mac_clean] = r["name"]
print("  MAC map: {} entries".format(len(mac_map)))

# Serial number → Service Equipment name
serial_map = {}
rows = frappe.db.sql("""
    SELECT name, serial_number FROM "tabService Equipment"
    WHERE serial_number IS NOT NULL AND serial_number != ''
""", as_dict=True)
for r in rows:
    serial_map[r["serial_number"].upper()] = r["name"]
print("  Serial map: {} entries".format(len(serial_map)))


# ═══════════════════════════════════════════════════════════════
# 1. WiFi provisioning → Service Equipment
# ═══════════════════════════════════════════════════════════════
print("\n" + "=" * 60)
print("1. WiFi PROVISIONING")
print("=" * 60)

# Group wifi entries by serial (keep latest / instance=1)
wifi_by_serial = {}
for w in wifi_entries:
    serial = w.get("serial", "")
    if not serial:
        continue
    instance = w.get("instance", 1)
    # Prefer instance 1 (primary SSID)
    if serial not in wifi_by_serial or instance == 1:
        wifi_by_serial[serial] = w
print("Unique WiFi serials: {}".format(len(wifi_by_serial)))

matched_wifi = 0
unmatched_wifi = 0

for serial, w in wifi_by_serial.items():
    ssid = w.get("ssid", "")
    password = w.get("password", "")
    if not ssid:
        continue

    # WiFi serial is typically a MAC address (Deco) — try MAC map
    mac_clean = serial.upper().replace(":", "").replace("-", "").replace(".", "")
    eq_name = mac_map.get(mac_clean)

    # Also try serial number map
    if not eq_name:
        eq_name = serial_map.get(serial.upper())

    # Try with common prefix patterns (TPLG...)
    if not eq_name:
        for prefix in ["TPLG", "TPLINK"]:
            eq_name = serial_map.get(prefix + serial.upper())
            if eq_name:
                break

    if not eq_name:
        unmatched_wifi += 1
        continue

    frappe.db.sql("""
        UPDATE "tabService Equipment"
        SET wifi_ssid = %(ssid)s, wifi_password = %(password)s
        WHERE name = %(name)s
    """, {"name": eq_name, "ssid": ssid, "password": password})
    matched_wifi += 1

frappe.db.commit()
print("WiFi matched: {} / unmatched: {}".format(matched_wifi, unmatched_wifi))


# ═══════════════════════════════════════════════════════════════
# 2. VoIP provisioning → Service Equipment
# ═══════════════════════════════════════════════════════════════
print("\n" + "=" * 60)
print("2. VoIP PROVISIONING")
print("=" * 60)

# Group voip entries by serial
voip_by_serial = {}
for v in voip_entries:
    serial = v.get("serial", "")
    if not serial:
        continue
    instance = v.get("instance", 1)
    if serial not in voip_by_serial or instance == 1:
        voip_by_serial[serial] = v
print("Unique VoIP serials: {}".format(len(voip_by_serial)))

matched_voip = 0
unmatched_voip = 0

for serial, v in voip_by_serial.items():
    username = v.get("username", "")
    password = v.get("password", "")
    if not username:
        continue

    # VoIP serial is typically RCMG physical serial — try serial map
    eq_name = serial_map.get(serial.upper())

    # Also try with RCMG prefix
    if not eq_name and not serial.upper().startswith("RCMG"):
        eq_name = serial_map.get("RCMG" + serial.upper())

    # Try MAC map (some CWMP serials encode MAC)
    if not eq_name:
        # Extract last 12 chars as potential MAC
        if len(serial) >= 12:
            potential_mac = serial[-12:].upper()
            eq_name = mac_map.get(potential_mac)

    if not eq_name:
        unmatched_voip += 1
        continue

    frappe.db.sql("""
        UPDATE "tabService Equipment"
        SET sip_username = %(username)s, sip_password = %(password)s
        WHERE name = %(name)s
    """, {"name": eq_name, "username": username, "password": password})
    matched_voip += 1

frappe.db.commit()
print("VoIP matched: {} / unmatched: {}".format(matched_voip, unmatched_voip))


# ═══════════════════════════════════════════════════════════════
# 3. DONE
# ═══════════════════════════════════════════════════════════════
print("\n" + "=" * 60)
print("PROVISIONING MIGRATION COMPLETE")
print("=" * 60)
print("WiFi: {} matched, {} unmatched".format(matched_wifi, unmatched_wifi))
print("VoIP: {} matched, {} unmatched".format(matched_voip, unmatched_voip))
print("")
print("Unmatched devices will be resolved after OLT query tagging (see ANALYSIS.md)")
