"""
Fix deliveries: restore catalog prices + create RAB-PROMO for discount absorption.

Handles BOTH:
  A) Deliveries with existing rebates (catalog restore + adjust rebate)
  B) Deliveries with NO rebate (catalog restore + create RAB-PROMO)

TEST MODE: Only runs on specific test accounts.
Set TEST_ACCOUNTS = None to run on ALL accounts.

Run inside erpnext-backend-1:
  /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/fix_no_rebate_discounts.py
"""
import frappe
import pymysql
import os
from datetime import datetime

DRY_RUN = False  # Set False to actually write

# Test on specific accounts only — set to None for all
# 3673 = Expro Transit, others from the 310 no-rebate list
TEST_ACCOUNTS = {3673, 263, 343, 264, 166}

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)
print("DRY_RUN:", DRY_RUN)

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

# ═══════════════════════════════════════════════════════════════
# STEP 1: Load legacy data
# ═══════════════════════════════════════════════════════════════
print("\n" + "=" * 60)
print("STEP 1: LOAD LEGACY DATA")
print("=" * 60)

with conn.cursor() as cur:
    cur.execute("""
        SELECT s.id, s.delivery_id, s.product_id, s.hijack, s.hijack_price, s.hijack_desc,
               p.sku, p.price as base_price, d.account_id
        FROM service s
        JOIN product p ON p.id = s.product_id
        JOIN delivery d ON d.id = s.delivery_id
        WHERE s.status = 1
        ORDER BY s.delivery_id, p.price DESC
    """)
    all_services = cur.fetchall()

conn.close()

# Group by delivery
deliveries = {}
for s in all_services:
    did = s["delivery_id"]
    if did not in deliveries:
        deliveries[did] = []
    base = float(s["base_price"] or 0)
    actual = float(s["hijack_price"]) if s["hijack"] else base
    is_rebate = base < 0
    deliveries[did].append({
        "svc_id": s["id"], "sku": s["sku"], "base_price": base,
        "actual_price": actual, "is_rebate": is_rebate,
        "hijack": s["hijack"],
        "hijack_desc": (s["hijack_desc"] or "").strip(),
        "account_id": s["account_id"],
    })

# Classify deliveries
no_rebate_cases = []
has_rebate_cases = []
for did, services in deliveries.items():
    acct_id = services[0]["account_id"]
    if TEST_ACCOUNTS and acct_id not in TEST_ACCOUNTS:
        continue

    has_discount = has_rebate = False
    discount_total = 0.0
    discount_services = []
    for s in services:
        if not s["is_rebate"] and s["actual_price"] < s["base_price"] - 0.01:
            has_discount = True
            discount_total += s["base_price"] - s["actual_price"]
            discount_services.append(s)
        if s["is_rebate"]:
            has_rebate = True

    if not has_discount:
        continue

    entry = {
        "delivery_id": did, "account_id": acct_id,
        "discount_total": round(discount_total, 2),
        "discount_services": discount_services, "all_services": services,
    }
    if has_rebate:
        has_rebate_cases.append(entry)
    else:
        no_rebate_cases.append(entry)

print("Test accounts: {}".format(TEST_ACCOUNTS or "ALL"))
print("Deliveries with existing rebate to adjust: {}".format(len(has_rebate_cases)))
print("Deliveries needing RAB-PROMO creation: {}".format(len(no_rebate_cases)))

# ═══════════════════════════════════════════════════════════════
# STEP 2: Ensure RAB-PROMO Item exists
# ═══════════════════════════════════════════════════════════════
print("\n" + "=" * 60)
print("STEP 2: ENSURE RAB-PROMO ITEM")
print("=" * 60)

rab_exists = frappe.db.sql("""
    SELECT name FROM "tabItem" WHERE name = 'RAB-PROMO'
""")

if not rab_exists:
    if not DRY_RUN:
        frappe.db.sql("""
            INSERT INTO "tabItem" (
                name, creation, modified, modified_by, owner, docstatus,
                item_code, item_name, item_group, description,
                is_stock_item, has_variants, disabled
            ) VALUES (
                'RAB-PROMO', NOW(), NOW(), 'Administrator', 'Administrator', 0,
                'RAB-PROMO', 'Rabais promotionnel', 'Rabais', 'Rabais promotionnel — créé automatiquement pour les services sans rabais existant',
                0, 0, 0
            )
        """)
        frappe.db.commit()
        print("  Created RAB-PROMO item")
    else:
        print("  [DRY RUN] Would create RAB-PROMO item")
else:
    print("  RAB-PROMO already exists")

# Also ensure Subscription Plan exists
plan_exists = frappe.db.sql("""
    SELECT name FROM "tabSubscription Plan" WHERE name = 'PLAN-RAB-PROMO'
""")

if not plan_exists:
    if not DRY_RUN:
        frappe.db.sql("""
            INSERT INTO "tabSubscription Plan" (
                name, creation, modified, modified_by, owner, docstatus,
                plan_name, item, cost, billing_interval, billing_interval_count,
                currency, price_determination
            ) VALUES (
                'PLAN-RAB-PROMO', NOW(), NOW(), 'Administrator', 'Administrator', 0,
                'PLAN-RAB-PROMO', 'RAB-PROMO', 0, 'Month', 1,
                'CAD', 'Fixed Rate'
            )
        """)
        frappe.db.commit()
        print("  Created PLAN-RAB-PROMO subscription plan")
    else:
        print("  [DRY RUN] Would create PLAN-RAB-PROMO subscription plan")
else:
    print("  PLAN-RAB-PROMO already exists")

# ═══════════════════════════════════════════════════════════════
# STEP 3: Map delivery_id → ERPNext Subscription + Customer
# ═══════════════════════════════════════════════════════════════
print("\n" + "=" * 60)
print("STEP 3: MAP LEGACY → ERPNEXT")
print("=" * 60)

# Get all subscriptions with legacy_service_id
subs = frappe.db.sql("""
    SELECT name, legacy_service_id, party, service_location, actual_price, item_code, status
    FROM "tabSubscription"
    WHERE legacy_service_id IS NOT NULL
""", as_dict=True)

sub_by_legacy = {}
for s in subs:
    lid = s.get("legacy_service_id")
    if lid:
        sub_by_legacy[lid] = s

print("Mapped ERPNext subscriptions: {}".format(len(sub_by_legacy)))

# Map account_id → customer
customers = frappe.db.sql("""
    SELECT name, legacy_account_id FROM "tabCustomer"
    WHERE legacy_account_id IS NOT NULL
""", as_dict=True)

cust_by_acct = {}
for c in customers:
    aid = c.get("legacy_account_id")
    if aid:
        cust_by_acct[int(aid)] = c["name"]

print("Mapped customers: {}".format(len(cust_by_acct)))

# ═══════════════════════════════════════════════════════════════
# STEP 4: Process each delivery
# ═══════════════════════════════════════════════════════════════
print("\n" + "=" * 60)
print("STEP 4: CREATE RAB-PROMO SUBSCRIPTIONS")
print("=" * 60)

created = 0
updated = 0
skipped_no_customer = 0
skipped_no_sub = 0
errors = 0

for case in no_rebate_cases:
    did = case["delivery_id"]
    acct_id = case["account_id"]
    discount = case["discount_total"]

    # Find customer + service_location from existing subscriptions (not from legacy_account_id)
    service_location = None
    customer = None
    any_sub = None
    for s in case["all_services"]:
        erp_sub = sub_by_legacy.get(s["svc_id"])
        if erp_sub:
            service_location = erp_sub.get("service_location")
            customer = erp_sub.get("party")
            any_sub = erp_sub
            break

    if not customer:
        # Fallback to legacy_account_id mapping
        customer = cust_by_acct.get(acct_id)

    if not customer:
        skipped_no_customer += 1
        continue

    if not any_sub:
        skipped_no_sub += 1
        continue

    # Build description from hijack_desc of discount services
    descs = []
    for s in case["discount_services"]:
        if s["hijack_desc"]:
            descs.append(s["hijack_desc"])
    description = "; ".join(descs) if descs else "Rabais loyauté"

    # Step 4a: Update positive products to catalog price
    for s in case["discount_services"]:
        erp_sub = sub_by_legacy.get(s["svc_id"])
        if erp_sub:
            # If it's a "fake rebate" (positive product with negative actual), restore to 0
            # If it's a discounted positive, restore to base_price
            if s["actual_price"] < 0:
                new_price = 0  # Was used as a discount line, zero it out
            else:
                new_price = s["base_price"]

            if not DRY_RUN:
                frappe.db.sql("""
                    UPDATE "tabSubscription"
                    SET actual_price = %s
                    WHERE name = %s
                """, (new_price, erp_sub["name"]))
            updated += 1

    # Step 4b: Create RAB-PROMO subscription
    rabais_name = "SUB-RAB-{}-{}".format(did, acct_id)

    # Check if already exists
    existing = frappe.db.sql("""
        SELECT name FROM "tabSubscription" WHERE name = %s
    """, (rabais_name,))

    if existing:
        continue

    if not DRY_RUN:
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        today = datetime.now().strftime("%Y-%m-%d")

        # Insert subscription
        frappe.db.sql("""
            INSERT INTO "tabSubscription" (
                name, creation, modified, modified_by, owner, docstatus,
                party_type, party, service_location, status,
                actual_price, custom_description, item_code, item_group,
                item_name, billing_frequency,
                start_date
            ) VALUES (
                %s, %s, %s, 'Administrator', 'Administrator', 0,
                'Customer', %s, %s, 'Active',
                %s, %s, 'RAB-PROMO', 'Rabais',
                'Rabais promotionnel', 'M',
                %s
            )
        """, (
            rabais_name, now, now,
            customer, service_location,
            -discount, description,
            today,
        ))

        # Insert Subscription Plan Detail child
        spd_name = "{}-plan".format(rabais_name)
        frappe.db.sql("""
            INSERT INTO "tabSubscription Plan Detail" (
                name, creation, modified, modified_by, owner, docstatus,
                parent, parentfield, parenttype, idx,
                plan, qty
            ) VALUES (
                %s, %s, %s, 'Administrator', 'Administrator', 0,
                %s, 'plans', 'Subscription', 1,
                'PLAN-RAB-PROMO', 1
            )
        """, (spd_name, now, now, rabais_name))

    created += 1

    if created % 50 == 0 and created > 0 and not DRY_RUN:
        frappe.db.commit()
        print("  Processed {}/{}...".format(created, len(no_rebate_cases)))

if not DRY_RUN:
    frappe.db.commit()

print("\nRAB-PROMO subscriptions created: {}".format(created))
print("Positive products price-restored: {}".format(updated))
print("Skipped (no customer in ERP): {}".format(skipped_no_customer))
print("Skipped (no subscription in ERP): {}".format(skipped_no_sub))
print("Errors: {}".format(errors))

# ═══════════════════════════════════════════════════════════════
# STEP 5: FIX DELIVERIES WITH EXISTING REBATES
# ═══════════════════════════════════════════════════════════════
print("\n" + "=" * 60)
print("STEP 5: FIX DELIVERIES WITH EXISTING REBATES")
print("=" * 60)

clean_adjusted = 0
rebates_adjusted = 0

for case in has_rebate_cases:
    services = case["all_services"]
    discount_to_absorb = case["discount_total"]

    biggest_rebate = min(
        [s for s in services if s["is_rebate"]],
        key=lambda s: s["actual_price"]
    )

    # Update positive products to catalog price
    for s in case["discount_services"]:
        erp_sub = sub_by_legacy.get(s["svc_id"])
        if erp_sub:
            new_price = s["base_price"] if s["actual_price"] >= 0 else 0
            if not DRY_RUN:
                frappe.db.sql("""
                    UPDATE "tabSubscription"
                    SET actual_price = %s
                    WHERE name = %s
                """, (new_price, erp_sub["name"]))
            clean_adjusted += 1

    # Update biggest rebate to absorb difference
    rebate_sub = sub_by_legacy.get(biggest_rebate["svc_id"])
    if rebate_sub:
        new_rebate_price = biggest_rebate["actual_price"] - discount_to_absorb
        if not DRY_RUN:
            frappe.db.sql("""
                UPDATE "tabSubscription"
                SET actual_price = %s
                WHERE name = %s
            """, (round(new_rebate_price, 2), rebate_sub["name"]))
        rebates_adjusted += 1

if not DRY_RUN:
    frappe.db.commit()

print("Positive products restored to catalog: {}".format(clean_adjusted))
print("Rebates adjusted to absorb discount: {}".format(rebates_adjusted))

# ═══════════════════════════════════════════════════════════════
# STEP 6: VERIFY ALL TEST ACCOUNTS
# ═══════════════════════════════════════════════════════════════
print("\n" + "=" * 60)
print("STEP 6: VERIFY TEST ACCOUNTS")
print("=" * 60)

if TEST_ACCOUNTS:
    for acct_id in sorted(TEST_ACCOUNTS):
        # Find customer from subscriptions (more reliable than legacy_account_id)
        customer = None
        for did_check, svcs_check in deliveries.items():
            if svcs_check[0]["account_id"] == acct_id:
                for sc in svcs_check:
                    erp_sc = sub_by_legacy.get(sc["svc_id"])
                    if erp_sc:
                        customer = erp_sc["party"]
                        break
                if customer:
                    break
        if not customer:
            customer = cust_by_acct.get(acct_id)
        if not customer:
            print("\n  Account {} — no customer in ERP".format(acct_id))
            continue

        cust_info = frappe.db.sql("""
            SELECT customer_name FROM "tabCustomer" WHERE name = %s
        """, (customer,), as_dict=True)
        cust_name = cust_info[0]["customer_name"] if cust_info else customer

        subs_list = frappe.db.sql("""
            SELECT name, item_code, item_name, actual_price, custom_description,
                   service_location, status
            FROM "tabSubscription"
            WHERE party = %s
            ORDER BY service_location, actual_price DESC
        """, (customer,), as_dict=True)

        print("\n  {} (account {}) — {} subs".format(cust_name, acct_id, len(subs_list)))
        current_loc = None
        loc_total = 0
        grand_total = 0
        for s in subs_list:
            loc = s.get("service_location") or "?"
            if loc != current_loc:
                if current_loc:
                    print("      SUBTOTAL: ${:.2f}".format(loc_total))
                current_loc = loc
                loc_total = 0
                print("    [{}]".format(loc[:60]))
            price = float(s["actual_price"] or 0)
            loc_total += price
            grand_total += price
            is_rab = price < 0
            indent = "      " if is_rab else "    "
            desc = s.get("custom_description") or ""
            print("  {}{:<14} {:>8.2f}  {}{}".format(
                indent, (s["item_code"] or "")[:14], price,
                (s["item_name"] or "")[:40],
                "  [{}]".format(desc[:40]) if desc else ""))
        if current_loc:
            print("      SUBTOTAL: ${:.2f}".format(loc_total))
        print("    GRAND TOTAL: ${:.2f}".format(grand_total))

# Global stats
total_subs = frappe.db.sql('SELECT COUNT(*) FROM "tabSubscription"')[0][0]
rab_promo_count = frappe.db.sql(
    'SELECT COUNT(*) FROM "tabSubscription" WHERE item_code = %s', ('RAB-PROMO',)
)[0][0]
print("\nTotal subscriptions: {}".format(total_subs))
print("RAB-PROMO subscriptions: {}".format(rab_promo_count))

frappe.clear_cache()
print("\nDone — cache cleared")
