"""
Create Website Users for customer portal + store legacy MD5 password hashes.
Bridge auth: on first login, verify MD5 → convert to pbkdf2 → clear legacy hash.

Requires custom field 'legacy_password_md5' (Data) on User doctype.

Run inside erpnext-backend-1:
  /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/create_portal_users.py
"""
import os, sys, time
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)

os.chdir("/home/frappe/frappe-bench/sites")
import frappe
frappe.init(site="erp.gigafibre.ca", sites_path=".")
frappe.connect()
# Disable rate limiting for bulk user creation
frappe.flags.in_migrate = True
frappe.flags.in_install = True
print("Connected:", frappe.local.site)

import pymysql

DRY_RUN = False  # SET TO False WHEN READY

# ── Step 1: Ensure custom field exists ──
print("\n" + "=" * 60)
print("Step 1: Ensure legacy_password_md5 custom field on User")
print("=" * 60)

if not frappe.db.exists('Custom Field', {'dt': 'User', 'fieldname': 'legacy_password_md5'}):
    if not DRY_RUN:
        cf = frappe.get_doc({
            'doctype': 'Custom Field',
            'dt': 'User',
            'fieldname': 'legacy_password_md5',
            'label': 'Legacy Password (MD5)',
            'fieldtype': 'Data',
            'hidden': 1,
            'no_copy': 1,
            'print_hide': 1,
            'insert_after': 'last_password_reset_date',
        })
        cf.insert(ignore_permissions=True)
        frappe.db.commit()
        print("  Created custom field")
    else:
        print("  [DRY RUN] Would create custom field")
else:
    print("  Custom field already exists")

# ── Step 2: Fetch legacy accounts with email + password ──
print("\n" + "=" * 60)
print("Step 2: Fetch legacy accounts")
print("=" * 60)

legacy = pymysql.connect(
    host="legacy-db", user="facturation", password="***LEGACY-DB-PW-REDACTED***",
    database="gestionclient", cursorclass=pymysql.cursors.DictCursor
)

with legacy.cursor() as cur:
    cur.execute("""
        SELECT id, email, password, first_name, last_name,
               status, customer_id
        FROM account
        WHERE email IS NOT NULL AND email != '' AND TRIM(email) != ''
          AND password IS NOT NULL AND password != ''
        ORDER BY id
    """)
    legacy_accounts = cur.fetchall()
legacy.close()

print(f"  Legacy accounts with email + password: {len(legacy_accounts)}")

# ── Step 3: Build legacy_account_id → Customer name map ──
acct_to_cust = {}
rows = frappe.db.sql('SELECT name, legacy_account_id FROM "tabCustomer" WHERE legacy_account_id IS NOT NULL', as_dict=True)
for r in rows:
    acct_to_cust[int(r['legacy_account_id'])] = r['name']
print(f"  Customers with legacy_account_id: {len(acct_to_cust)}")

# ── Step 4: Check existing users ──
existing_users = set()
rows = frappe.db.sql('SELECT LOWER(name) as name FROM "tabUser"', as_dict=True)
for r in rows:
    existing_users.add(r['name'])

print(f"  Existing ERPNext users: {len(existing_users)}")

# ── Step 5: Create Website Users ──
print("\n" + "=" * 60)
print("Step 3: Create Website Users")
print("=" * 60)

t0 = time.time()
created = 0
skipped_existing = 0
skipped_no_customer = 0
skipped_bad_email = 0
errors = 0

for acc in legacy_accounts:
    email = acc['email'].strip().lower()

    # Basic email validation
    if '@' not in email or '.' not in email.split('@')[-1]:
        skipped_bad_email += 1
        continue

    # Already exists?
    if email in existing_users:
        # Just update the legacy hash if not already set
        if not DRY_RUN and acc['password']:
            try:
                frappe.db.sql(
                    """UPDATE "tabUser" SET legacy_password_md5 = %s
                       WHERE LOWER(name) = %s AND (legacy_password_md5 IS NULL OR legacy_password_md5 = '')""",
                    (acc['password'], email)
                )
            except Exception:
                pass  # Field might not exist yet in dry run
        skipped_existing += 1
        continue

    # Find the ERPNext customer via legacy_account_id
    cust_name = acct_to_cust.get(int(acc['id']))

    if not cust_name:
        skipped_no_customer += 1
        continue

    first_name = (acc.get('first_name') or '').strip() or 'Client'
    last_name = (acc.get('last_name') or '').strip() or ''
    full_name = f"{first_name} {last_name}".strip()

    if not DRY_RUN:
        try:
            user = frappe.get_doc({
                'doctype': 'User',
                'email': email,
                'first_name': first_name,
                'last_name': last_name,
                'full_name': full_name,
                'enabled': 1,
                'user_type': 'Website User',
                'legacy_password_md5': acc['password'] or '',
                'roles': [{'role': 'Customer'}],
            })
            user.flags.no_welcome_email = True  # Don't send email yet
            user.flags.ignore_permissions = True
            user.flags.in_import = True
            user.insert(ignore_permissions=True, ignore_if_duplicate=True)
            created += 1

            # Link user to customer as portal user
            customer_doc = frappe.get_doc('Customer', cust_name)
            customer_doc.append('portal_users', {'user': email})
            customer_doc.save(ignore_permissions=True)

        except frappe.DuplicateEntryError:
            skipped_existing += 1
        except Exception as e:
            errors += 1
            if errors <= 10:
                print(f"    ERR {email}: {e}")
    else:
        created += 1  # Count as would-create

    if (created + skipped_existing) % 1000 == 0:
        if not DRY_RUN:
            frappe.db.commit()
        elapsed = time.time() - t0
        total = created + skipped_existing + skipped_no_customer + skipped_bad_email + errors
        print(f"    Progress: {total}/{len(legacy_accounts)} created={created} existing={skipped_existing} [{elapsed:.0f}s]")

if not DRY_RUN:
    frappe.db.commit()

elapsed = time.time() - t0
print(f"\n  Created: {created}")
print(f"  Already existed: {skipped_existing}")
print(f"  No matching customer: {skipped_no_customer}")
print(f"  Bad email: {skipped_bad_email}")
print(f"  Errors: {errors}")
print(f"  Time: {elapsed:.0f}s")

if DRY_RUN:
    print("\n  ** DRY RUN — no changes made **")

print("\n" + "=" * 60)
print("DONE")
print("=" * 60)
