"""Reclassify server 'computer' assets into 'network_device' assets.

Servers were imported as computers (a PC type), so they show under PCs instead
of Network. This re-points each server's asset in place - the assetid does NOT
change, so its communications, relationships, map position, name, location, and
audit history all carry over. Only the extension row is swapped (computers ->
networkdevices) and the asset's type is flipped, and the network device is given
the 'Server' networkdevicetype.

Identify servers by a name/hostname prefix (default 'SVR-'), or pass --type to
match an exact computer type instead.

Usage (on the target instance, in the app dir):
    DATABASE_URL=... venv/bin/python scripts/reclassify_servers_to_network.py            # dry run
    DATABASE_URL=... venv/bin/python scripts/reclassify_servers_to_network.py --commit   # apply
    ... --type "Server" --commit
"""

import argparse
import os
import sys

# Run from anywhere: put the repo root (parent of scripts/) on the path.
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from shopdb import create_app
from shopdb.api import db
from shopdb.core.models import Asset, AssetType
from plugins.computers.models import Computer, ComputerType
from plugins.network.models import NetworkDevice, NetworkDeviceType


def _get_or_create_networkdevicetype(name):
    ndt = NetworkDeviceType.query.filter_by(networkdevicetype=name).first()
    if not ndt:
        ndt = NetworkDeviceType(networkdevicetype=name,
                                description='Server (reclassified from PCs)')
        db.session.add(ndt)
        db.session.flush()
    return ndt


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    group = parser.add_mutually_exclusive_group()
    group.add_argument('--prefix', default='SVR-',
                       help="match servers by name/assetnumber/hostname starting "
                            "with this (default 'SVR-')")
    group.add_argument('--type',
                       help="instead of --prefix, match by an exact computer type name")
    parser.add_argument('--commit', action='store_true',
                        help='apply the change; without it this is a dry run')
    args = parser.parse_args()

    app = create_app()
    with app.app_context():
        nd_assettype = AssetType.query.filter_by(assettype='network_device').first()
        if not nd_assettype:
            sys.exit("No 'network_device' asset type - is the network plugin installed?")

        query = Computer.query.join(Asset)
        if args.type:
            ctype = ComputerType.query.filter_by(computertype=args.type).first()
            if not ctype:
                sys.exit("No computer type named %r." % args.type)
            query = query.filter(Computer.computertypeid == ctype.computertypeid)
            criterion = "computer type %r" % args.type
        else:
            like = args.prefix + '%'
            query = query.filter(db.or_(
                Asset.assetnumber.like(like),
                Asset.name.like(like),
                Computer.hostname.like(like),
            ))
            criterion = "name/hostname prefix %r" % args.prefix

        servers = query.all()
        if not servers:
            print("No computers match %s - nothing to do." % criterion)
            return

        ndt = _get_or_create_networkdevicetype('Server')
        print("%d server(s) matching %s -> network_device / type 'Server':"
              % (len(servers), criterion))

        moved = 0
        for computer in servers:
            asset = computer.asset
            if not asset:
                continue
            label = asset.name or asset.assetnumber or ('asset %d' % asset.assetid)
            print("  - %s (assetid %d)" % (label, asset.assetid))
            if args.commit:
                # Swap extension: create the network device on the SAME asset,
                # re-point the asset's type, then drop the computer extension.
                asset.assettypeid = nd_assettype.assettypeid
                db.session.add(NetworkDevice(
                    assetid=asset.assetid,
                    networkdevicetypeid=ndt.networkdevicetypeid,
                    hostname=getattr(computer, 'hostname', None),
                    vendorid=getattr(computer, 'vendorid', None),
                ))
                db.session.delete(computer)   # asset stays (FK cascade is asset->computer)
                moved += 1

        if args.commit:
            db.session.commit()
            print("\nDone: %d reclassified. They now appear under Network." % moved)
        else:
            print("\nDRY RUN - nothing changed. Re-run with --commit to apply.")


if __name__ == '__main__':
    main()
