#!/usr/bin/env python3
"""
Import data from legacy MySQL ShopDB to new Flask ShopDB.

Usage:
    cd /home/camp/projects/shopdb-flask
    source venv/bin/activate
    python scripts/import_from_mysql.py
"""

import os
import sys
import pymysql
from datetime import datetime
from dotenv import load_dotenv

# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# Load environment variables
load_dotenv(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), '.env'))

# MySQL connection settings
MYSQL_CONFIG = {
    'host': '127.0.0.1',
    'port': 3306,
    'user': 'root',
    'password': 'rootpassword',
    'database': 'shopdb',
    'charset': 'utf8mb4',
    'cursorclass': pymysql.cursors.DictCursor
}


def get_mysql_connection():
    """Get MySQL connection."""
    return pymysql.connect(**MYSQL_CONFIG)


def import_vendors(mysql_conn, db, Vendor):
    """Import vendors from MySQL."""
    print("Importing vendors...")
    cursor = mysql_conn.cursor()
    cursor.execute("SELECT * FROM vendors WHERE isactive = 1")
    vendors = cursor.fetchall()

    count = 0
    for v in vendors:
        existing = Vendor.query.filter_by(vendor=v['vendor']).first()
        if not existing:
            vendor = Vendor(
                vendor=v['vendor'],
                isactive=True
            )
            db.session.add(vendor)
            count += 1

    db.session.commit()
    print(f"  Imported {count} vendors")
    return count


def import_machinetypes(mysql_conn, db, MachineType):
    """Import machine types from MySQL with category mapping."""
    print("Importing machine types...")
    cursor = mysql_conn.cursor()
    cursor.execute("SELECT * FROM machinetypes WHERE isactive = 1")
    types = cursor.fetchall()

    # Category mapping based on machinetype name
    pc_types = ['PC']
    network_types = ['Access Point', 'IDF', 'Switch', 'Server', 'Camera']
    printer_types = ['Printer']

    count = 0
    for t in types:
        existing = MachineType.query.filter_by(machinetype=t['machinetype']).first()
        if not existing:
            # Determine category
            if t['machinetype'] in pc_types:
                category = 'PC'
            elif t['machinetype'] in network_types:
                category = 'Network'
            elif t['machinetype'] in printer_types:
                category = 'Printer'
            else:
                category = 'Equipment'

            mt = MachineType(
                machinetype=t['machinetype'],
                category=category,
                description=t.get('machinedescription'),
                isactive=True
            )
            db.session.add(mt)
            count += 1

    db.session.commit()
    print(f"  Imported {count} machine types")
    return count


def import_pctypes(mysql_conn, db, PCType):
    """Import PC types from MySQL."""
    print("Importing PC types...")
    cursor = mysql_conn.cursor()
    cursor.execute("SELECT * FROM pctype WHERE isactive = '1'")
    types = cursor.fetchall()

    count = 0
    for t in types:
        existing = PCType.query.filter_by(pctype=t['typename']).first()
        if not existing:
            pctype = PCType(
                pctype=t['typename'],
                description=t.get('description'),
                isactive=True
            )
            db.session.add(pctype)
            count += 1

    db.session.commit()
    print(f"  Imported {count} PC types")
    return count


def import_businessunits(mysql_conn, db, BusinessUnit):
    """Import business units from MySQL."""
    print("Importing business units...")
    cursor = mysql_conn.cursor()
    cursor.execute("SELECT * FROM businessunits WHERE isactive = 1")
    units = cursor.fetchall()

    count = 0
    for bu in units:
        existing = BusinessUnit.query.filter_by(businessunit=bu['businessunit']).first()
        if not existing:
            unit = BusinessUnit(
                businessunit=bu['businessunit'],
                isactive=True
            )
            db.session.add(unit)
            count += 1

    db.session.commit()
    print(f"  Imported {count} business units")
    return count


def import_statuses(mysql_conn, db, MachineStatus):
    """Import machine statuses from MySQL."""
    print("Importing machine statuses...")
    cursor = mysql_conn.cursor()
    cursor.execute("SELECT * FROM machinestatus WHERE isactive = 1")
    statuses = cursor.fetchall()

    count = 0
    for s in statuses:
        existing = MachineStatus.query.filter_by(status=s['machinestatus']).first()
        if not existing:
            status = MachineStatus(
                status=s['machinestatus'],
                description=s.get('statusdescription'),
                isactive=True
            )
            db.session.add(status)
            count += 1

    db.session.commit()
    print(f"  Imported {count} statuses")
    return count


def import_operatingsystems(mysql_conn, db, OperatingSystem):
    """Import operating systems from MySQL."""
    print("Importing operating systems...")
    cursor = mysql_conn.cursor()
    cursor.execute("SELECT * FROM operatingsystems")
    os_list = cursor.fetchall()

    count = 0
    for os_item in os_list:
        os_name = os_item.get('operatingsystem') or os_item.get('osname')
        if not os_name:
            continue

        existing = OperatingSystem.query.filter_by(osname=os_name).first()
        if not existing:
            os_obj = OperatingSystem(
                osname=os_name,
                osversion=os_item.get('osversion'),
                isactive=True
            )
            db.session.add(os_obj)
            count += 1

    db.session.commit()
    print(f"  Imported {count} operating systems")
    return count


def import_models(mysql_conn, db, Model, Vendor, MachineType):
    """Import models from MySQL."""
    print("Importing models...")
    cursor = mysql_conn.cursor()
    cursor.execute("""
        SELECT m.*, v.vendor as vendor_name, mt.machinetype as type_name
        FROM models m
        LEFT JOIN vendors v ON m.vendorid = v.vendorid
        LEFT JOIN machinetypes mt ON m.machinetypeid = mt.machinetypeid
        WHERE m.isactive = 1
    """)
    models = cursor.fetchall()

    count = 0
    for m in models:
        existing = Model.query.filter_by(modelnumber=m['modelnumber']).first()
        if not existing:
            # Find vendor and machinetype in new db
            vendor = Vendor.query.filter_by(vendor=m['vendor_name']).first() if m['vendor_name'] else None
            machinetype = MachineType.query.filter_by(machinetype=m['type_name']).first() if m['type_name'] else None

            model = Model(
                modelnumber=m['modelnumber'],
                vendorid=vendor.vendorid if vendor else None,
                machinetypeid=machinetype.machinetypeid if machinetype else None,
                notes=m.get('notes'),
                isactive=True
            )
            db.session.add(model)
            count += 1

    db.session.commit()
    print(f"  Imported {count} models")
    return count


def import_relationshiptypes(mysql_conn, db, RelationshipType):
    """Import relationship types from MySQL."""
    print("Importing relationship/connection types...")
    cursor = mysql_conn.cursor()
    cursor.execute("SELECT * FROM relationshiptypes WHERE isactive = 1")
    types = cursor.fetchall()

    count = 0
    for rt in types:
        existing = RelationshipType.query.filter_by(relationshiptype=rt['relationshiptype']).first()
        if not existing:
            rel_type = RelationshipType(
                relationshiptype=rt['relationshiptype'],
                description=rt.get('description'),
                isactive=True
            )
            db.session.add(rel_type)
            count += 1

    db.session.commit()
    print(f"  Imported {count} relationship types")
    return count


def import_machines(mysql_conn, db, Machine, MachineType, MachineStatus,
                   Vendor, Model, BusinessUnit, OperatingSystem, Location,
                   Communication, CommunicationType, PCType):
    """Import machines (Equipment and PCs) from MySQL."""
    print("Importing machines...")
    cursor = mysql_conn.cursor()

    # Get machines with related data
    cursor.execute("""
        SELECT m.*,
               mt.machinetype as type_name,
               ms.machinestatus as status_name,
               v.vendor as vendor_name,
               mdl.modelnumber as model_name,
               bu.businessunit as bu_name,
               os.operatingsystem as os_name,
               pt.typename as pctype_name
        FROM machines m
        LEFT JOIN machinetypes mt ON m.machinetypeid = mt.machinetypeid
        LEFT JOIN machinestatus ms ON m.machinestatusid = ms.machinestatusid
        LEFT JOIN models mdl ON m.modelnumberid = mdl.modelnumberid
        LEFT JOIN vendors v ON mdl.vendorid = v.vendorid
        LEFT JOIN businessunits bu ON m.businessunitid = bu.businessunitid
        LEFT JOIN operatingsystems os ON m.osid = os.osid
        LEFT JOIN pctype pt ON m.pctypeid = pt.pctypeid
        WHERE m.isactive = 1
    """)
    machines = cursor.fetchall()

    # Get or create IP communication type
    ip_comtype = CommunicationType.query.filter_by(comtype='IP').first()
    if not ip_comtype:
        ip_comtype = CommunicationType(comtype='IP', description='IP Network')
        db.session.add(ip_comtype)
        db.session.flush()

    # Build lookup maps
    type_map = {t.machinetype: t for t in MachineType.query.all()}
    status_map = {s.status: s for s in MachineStatus.query.all()}
    vendor_map = {v.vendor: v for v in Vendor.query.all()}
    model_map = {m.modelnumber: m for m in Model.query.all()}
    bu_map = {b.businessunit: b for b in BusinessUnit.query.all()}
    os_map = {o.osname: o for o in OperatingSystem.query.all()}
    pctype_map = {p.pctype: p for p in PCType.query.all()}

    # Track old->new ID mapping for relationships
    machine_id_map = {}

    count = 0
    comm_count = 0
    skipped = 0
    for m in machines:
        # Skip machines without a machinenumber
        if not m.get('machinenumber'):
            skipped += 1
            continue

        # Check if already exists
        existing = Machine.query.filter_by(machinenumber=m['machinenumber']).first()
        if existing:
            machine_id_map[m['machineid']] = existing.machineid
            continue

        # Get related objects
        machinetype = type_map.get(m['type_name'])
        status = status_map.get(m['status_name'])
        vendor = vendor_map.get(m['vendor_name'])
        model = model_map.get(m['model_name'])
        bu = bu_map.get(m['bu_name'])
        os_obj = os_map.get(m['os_name'])
        pctype = pctype_map.get(m['pctype_name'])

        machine = Machine(
            machinenumber=m['machinenumber'],
            alias=m.get('alias'),
            hostname=m.get('hostname'),
            serialnumber=m.get('serialnumber'),
            machinetypeid=machinetype.machinetypeid if machinetype else None,
            pctypeid=pctype.pctypeid if pctype else None,
            statusid=status.statusid if status else None,
            vendorid=vendor.vendorid if vendor else None,
            modelnumberid=model.modelnumberid if model else None,
            businessunitid=bu.businessunitid if bu else None,
            osid=os_obj.osid if os_obj else None,
            mapleft=m.get('mapleft'),
            maptop=m.get('maptop'),
            isvnc=bool(m.get('isvnc')),
            iswinrm=bool(m.get('iswinrm')),
            islocationonly=bool(m.get('islocationonly')),
            loggedinuser=m.get('loggedinuser'),
            notes=m.get('machinenotes'),
            isactive=True
        )
        db.session.add(machine)
        db.session.flush()  # Get the new ID

        machine_id_map[m['machineid']] = machine.machineid
        count += 1

        # Import IP addresses
        if m.get('ipaddress1'):
            comm = Communication(
                machineid=machine.machineid,
                comtypeid=ip_comtype.comtypeid,
                ipaddress=m['ipaddress1'],
                isprimary=True
            )
            db.session.add(comm)
            comm_count += 1

        if m.get('ipaddress2'):
            comm = Communication(
                machineid=machine.machineid,
                comtypeid=ip_comtype.comtypeid,
                ipaddress=m['ipaddress2'],
                isprimary=False
            )
            db.session.add(comm)
            comm_count += 1

    db.session.commit()
    print(f"  Imported {count} machines with {comm_count} IP addresses (skipped {skipped} invalid)")
    return machine_id_map


def import_relationships(mysql_conn, db, MachineRelationship, RelationshipType, machine_id_map):
    """Import machine relationships from MySQL."""
    print("Importing machine relationships...")
    cursor = mysql_conn.cursor()
    cursor.execute("""
        SELECT mr.*, rt.relationshiptype
        FROM machinerelationships mr
        JOIN relationshiptypes rt ON mr.relationshiptypeid = rt.relationshiptypeid
        WHERE mr.isactive = 1
    """)
    relationships = cursor.fetchall()

    # Build relationship type map
    type_map = {t.relationshiptype: t for t in RelationshipType.query.all()}

    count = 0
    skipped = 0
    for r in relationships:
        # Map old IDs to new IDs
        parent_id = machine_id_map.get(r['machineid'])
        child_id = machine_id_map.get(r['related_machineid'])

        if not parent_id or not child_id:
            skipped += 1
            continue

        rel_type = type_map.get(r['relationshiptype'])
        if not rel_type:
            skipped += 1
            continue

        # Check if already exists
        existing = MachineRelationship.query.filter_by(
            parentmachineid=parent_id,
            childmachineid=child_id,
            relationshiptypeid=rel_type.relationshiptypeid
        ).first()

        if not existing:
            relationship = MachineRelationship(
                parentmachineid=parent_id,
                childmachineid=child_id,
                relationshiptypeid=rel_type.relationshiptypeid,
                notes=r.get('relationship_notes')
            )
            db.session.add(relationship)
            count += 1

    db.session.commit()
    print(f"  Imported {count} relationships (skipped {skipped})")
    return count


def import_printers(mysql_conn, db, Machine, MachineType, Model, Vendor,
                   Communication, CommunicationType):
    """Import printers from MySQL."""
    print("Importing printers...")

    # First, ensure we have a Printer machine type
    printer_type = MachineType.query.filter_by(machinetype='Printer').first()
    if not printer_type:
        printer_type = MachineType(machinetype='Printer', category='Printer')
        db.session.add(printer_type)
        db.session.flush()

    # Get or create IP communication type
    ip_comtype = CommunicationType.query.filter_by(comtype='IP').first()
    if not ip_comtype:
        ip_comtype = CommunicationType(comtype='IP', description='IP Network')
        db.session.add(ip_comtype)
        db.session.flush()

    cursor = mysql_conn.cursor()
    cursor.execute("""
        SELECT p.*, m.modelnumber, v.vendor as vendor_name
        FROM printers p
        LEFT JOIN models m ON p.modelid = m.modelnumberid
        LEFT JOIN vendors v ON m.vendorid = v.vendorid
        WHERE p.isactive = 1
    """)
    printers = cursor.fetchall()

    # Build lookup maps
    model_map = {m.modelnumber: m for m in Model.query.all()}
    vendor_map = {v.vendor: v for v in Vendor.query.all()}

    count = 0
    comm_count = 0
    for p in printers:
        # Use windows name as machine number
        machine_number = p.get('printerwindowsname') or f"Printer_{p['printerid']}"

        existing = Machine.query.filter_by(machinenumber=machine_number).first()
        if existing:
            continue

        model = model_map.get(p.get('modelnumber'))
        vendor = vendor_map.get(p.get('vendor_name'))

        machine = Machine(
            machinenumber=machine_number,
            alias=p.get('printercsfname'),
            hostname=p.get('fqdn'),
            serialnumber=p.get('serialnumber'),
            machinetypeid=printer_type.machinetypeid,
            vendorid=vendor.vendorid if vendor else None,
            modelnumberid=model.modelnumberid if model else None,
            mapleft=p.get('mapleft'),
            maptop=p.get('maptop'),
            notes=p.get('printernotes'),
            isactive=True
        )
        db.session.add(machine)
        db.session.flush()
        count += 1

        # Import IP address
        if p.get('ipaddress'):
            comm = Communication(
                machineid=machine.machineid,
                comtypeid=ip_comtype.comtypeid,
                ipaddress=p['ipaddress'],
                isprimary=True
            )
            db.session.add(comm)
            comm_count += 1

    db.session.commit()
    print(f"  Imported {count} printers with {comm_count} IP addresses")
    return count


def main():
    """Main import function."""
    print("=" * 60)
    print("ShopDB MySQL to Flask Migration")
    print("=" * 60)

    # Initialize Flask app
    from shopdb import create_app
    from shopdb.extensions import db
    from shopdb.core.models import (
        Machine, MachineType, MachineStatus, Vendor, Model,
        BusinessUnit, OperatingSystem, Location, PCType
    )
    from shopdb.core.models.communication import Communication, CommunicationType
    from shopdb.core.models.relationship import MachineRelationship, RelationshipType

    app = create_app()

    with app.app_context():
        # Connect to MySQL
        print("\nConnecting to MySQL...")
        mysql_conn = get_mysql_connection()
        print("  Connected!")

        try:
            # Import reference data
            print("\n--- Reference Data ---")
            import_vendors(mysql_conn, db, Vendor)
            import_machinetypes(mysql_conn, db, MachineType)
            import_pctypes(mysql_conn, db, PCType)
            import_businessunits(mysql_conn, db, BusinessUnit)
            import_statuses(mysql_conn, db, MachineStatus)
            import_operatingsystems(mysql_conn, db, OperatingSystem)
            import_models(mysql_conn, db, Model, Vendor, MachineType)
            import_relationshiptypes(mysql_conn, db, RelationshipType)

            # Import machines
            print("\n--- Machines ---")
            machine_id_map = import_machines(
                mysql_conn, db, Machine, MachineType, MachineStatus,
                Vendor, Model, BusinessUnit, OperatingSystem, Location,
                Communication, CommunicationType, PCType
            )

            # Import relationships
            print("\n--- Relationships ---")
            import_relationships(mysql_conn, db, MachineRelationship, RelationshipType, machine_id_map)

            # Import printers
            print("\n--- Printers ---")
            import_printers(mysql_conn, db, Machine, MachineType, Model, Vendor,
                          Communication, CommunicationType)

            print("\n" + "=" * 60)
            print("Import complete!")
            print("=" * 60)

        finally:
            mysql_conn.close()


if __name__ == '__main__':
    main()
