"""
Import machines from Cantaloupe Excel export into assets.db.
Maps Excel columns to DB fields, creates/finds customers and locations.

Usage: python3 import_machines.py <excel_path>
"""

import openpyxl, sqlite3, sys, re, os
from datetime import datetime

DB = '/home/oplabs/projects/canteen-asset-tracker/assets.db'

def norm(s):
    """Normalize a string for comparison."""
    if s is None:
        return ''
    return str(s).strip().lower()

def _sanitize_machine_id(mid):
    if not mid:
        return ''
    return str(mid).strip()[:100]

def main(xlsx_path):
    if not os.path.exists(xlsx_path):
        print(f'ERROR: File not found: {xlsx_path}')
        return 1

    wb = openpyxl.load_workbook(xlsx_path, data_only=True)
    ws = wb['Machine List']

    # Read all rows
    rows = []
    for row in ws.iter_rows(min_row=2, values_only=True):
        if row[2] is None:
            continue
        rows.append(row)

    print(f'Loaded {len(rows)} machines from Excel')

    conn = sqlite3.connect(DB)
    conn.execute("PRAGMA journal_mode=WAL")

    # Pre-load existing customers
    existing_customers = {}
    for r in conn.execute("SELECT id, name FROM customers").fetchall():
        existing_customers[norm(r[1])] = r[0]

    # Pre-load existing assets by machine_id for upsert
    existing_assets = {}
    for r in conn.execute("SELECT id, machine_id FROM assets WHERE machine_id IS NOT NULL").fetchall():
        existing_assets[_sanitize_machine_id(r[1])] = r[0]

    # Stats
    stats = {'created': 0, 'updated': 0, 'skipped': 0, 'errors': 0}

    # Build customer cache - keep a set of customer names we've already seen in this import
    customer_cache = set()

    # Process in a single transaction
    for idx, row in enumerate(rows):
        try:
            machine_id = _sanitize_machine_id(str(int(row[2])))
            location_str = str(row[1]) if row[1] else ''   # "Company - Address"
            customer_name = str(row[21]) if row[21] else '' # Customer
            is_disney = 1 if customer_name.strip().startswith('D-') else 0
            address = str(row[6]) if row[6] else ''
            city = str(row[5]) if row[5] else ''
            state = str(row[33]) if row[33] else ''
            postal = str(row[34]) if row[34] else ''
            serial = str(row[37]) if row[37] else ''
            make = str(row[39]) if row[39] else 'Unknown'
            model = str(row[40]) if row[40] else 'Unknown'
            cls = str(row[38]) if row[38] else 'Other'  # Class → category
            branch = str(row[51]) if row[51] else ''

            # New columns from export
            dex_report_date = row[7]
            if isinstance(dex_report_date, datetime):
                dex_report_date = dex_report_date.strftime('%Y-%m-%d %H:%M:%S')
            else:
                dex_report_date = str(dex_report_date) if dex_report_date else ''
            deployed = str(row[34]) if row[34] else ''
            pulled_date = row[35]
            if isinstance(pulled_date, datetime):
                pulled_date = pulled_date.strftime('%Y-%m-%d %H:%M:%S')
            else:
                pulled_date = str(pulled_date) if pulled_date else ''
            device = str(row[0]) if row[0] else ''

            # Asset name: use location string if available, else customer + address
            name = location_str if location_str else (customer_name + ' - ' + address if address else machine_id)
            name = name.strip()[:200]

            # Build full address
            full_address_parts = [p for p in [address, city, state, postal] if p]
            full_address = ', '.join(full_address_parts) if full_address_parts else ''
            full_address = full_address[:200]

            # Category: map from class (normalize GF prefix casing)
            category_map = {
                'snack': 'Snack', 'drink': 'Drink', 'cold drink': 'Drink',
                'combo': 'Combo', 'food': 'Food', 'other': 'Other',
                'unknown': 'Other',
                'gf bev': 'Bev', 'gf food': 'Food',
                'bev': 'Bev', 'snack/bev': 'Snack/bev',
                'snack/food': 'Snack/food',
            }
            cat = category_map.get(cls.strip().lower(), cls.capitalize() if cls else 'Other')

            # Status: always active for import (Cantaloupe RPC status is telemetry, not condition)
            status = 'active'

            # ----- Customer resolution -----
            customer_id = None
            if customer_name:
                key = norm(customer_name)
                if key in existing_customers:
                    customer_id = existing_customers[key]
                else:
                    # Create new customer
                    c = conn.execute(
                        "INSERT INTO customers (name) VALUES (?)",
                        (customer_name.strip()[:100],)
                    )
                    customer_id = c.lastrowid
                    existing_customers[key] = customer_id
                    print(f'  Created customer: {customer_name.strip()[:60]}')

            # ----- Upsert logic -----
            if machine_id in existing_assets:
                aid = existing_assets[machine_id]
                # Update existing - preserve disney_park, GPS, keys, badges
                conn.execute("""
                    UPDATE assets SET
                        name = ?,
                        serial_number = ?,
                        make = ?,
                        model = ?,
                        category = ?,
                        address = ?,
                        customer_id = COALESCE(?, customer_id),
                        description = ?,
                        dex_report_date = ?,
                        deployed = ?,
                        pulled_date = ?,
                        updated_at = datetime('now')
                    WHERE id = ?
                """, (name, serial, make, model, cat, full_address,
                      customer_id,
                      device + ' | Branch: ' + branch if branch else device,
                      dex_report_date or None, deployed or None, pulled_date or None,
                      aid))
                stats['updated'] += 1
            else:
                # Insert new
                cursor = conn.execute("""
                    INSERT INTO assets
                        (machine_id, name, serial_number, make, model, category,
                         status, address, customer_id, is_disney,
                         dex_report_date, deployed, pulled_date,
                         created_at, updated_at, description)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'), datetime('now'), ?)
                """, (machine_id, name, serial, make, model, cat,
                      status, full_address, customer_id, is_disney,
                      dex_report_date or None, deployed or None, pulled_date or None,
                      device + ' | Branch: ' + branch if branch else device))
                aid = cursor.lastrowid
                existing_assets[machine_id] = aid
                stats['created'] += 1

        except Exception as e:
            print(f'ERROR row {idx+2} (machine_id={row[2]}): {e}')
            stats['errors'] += 1

    conn.commit()
    conn.close()

    print()
    print(f'=== Import Complete ===')
    print(f'  Created:     {stats["created"]} new assets')
    print(f'  Updated:     {stats["updated"]} existing assets')
    print(f'  Skipped:     {stats["skipped"]}')
    print(f'  Errors:      {stats["errors"]}')
    print(f'  Total rows:  {len(rows)}')

    return 0 if stats['errors'] == 0 else 1


if __name__ == '__main__':
    if len(sys.argv) < 2:
        print('Usage: python3 import_machines.py <excel.xlsx>')
        sys.exit(1)
    sys.exit(main(sys.argv[1]))
