"""USB plugin API endpoints."""

from flask import Blueprint, request
from flask_jwt_extended import jwt_required, get_jwt_identity
from datetime import datetime

from shopdb.extensions import db
from shopdb.core.models import AuditLog
from shopdb.utils.responses import (
    success_response,
    error_response,
    paginated_response,
    ErrorCodes
)
from shopdb.utils.pagination import get_pagination_params, paginate_query

from ..models import USBDevice, USBDeviceType, USBCheckout

usb_bp = Blueprint('usb', __name__)


# =============================================================================
# USB Device Types
# =============================================================================

@usb_bp.route('/types', methods=['GET'])
@jwt_required(optional=True)
def list_device_types():
    """List all USB device types."""
    types = USBDeviceType.query.filter_by(isactive=True).order_by(USBDeviceType.typename).all()
    return success_response([{
        'usbdevicetypeid': t.usbdevicetypeid,
        'typename': t.typename,
        'description': t.description,
        'icon': t.icon
    } for t in types])


@usb_bp.route('/types', methods=['POST'])
@jwt_required()
def create_device_type():
    """Create a new USB device type."""
    data = request.get_json() or {}

    if not data.get('typename'):
        return error_response(ErrorCodes.VALIDATION_ERROR, 'typename is required')

    if USBDeviceType.query.filter_by(typename=data['typename']).first():
        return error_response(ErrorCodes.CONFLICT, 'Type name already exists', http_code=409)

    device_type = USBDeviceType(
        typename=data['typename'],
        description=data.get('description'),
        icon=data.get('icon', 'usb')
    )

    db.session.add(device_type)
    db.session.commit()

    return success_response({
        'usbdevicetypeid': device_type.usbdevicetypeid,
        'typename': device_type.typename
    }, message='Device type created', http_code=201)


# =============================================================================
# USB Devices
# =============================================================================

@usb_bp.route('', methods=['GET'])
@jwt_required(optional=True)
def list_usb_devices():
    """
    List all USB devices with checkout status.

    Query parameters:
    - page, per_page: Pagination
    - search: Search by serial number, label, or asset number
    - available: Filter to only available (not checked out) devices
    - typeid: Filter by device type ID
    """
    page, per_page = get_pagination_params(request)

    query = USBDevice.query.filter_by(isactive=True)

    # Filter by type
    if type_id := request.args.get('typeid'):
        query = query.filter_by(usbdevicetypeid=int(type_id))

    # Filter by checkout status
    if request.args.get('available', '').lower() == 'true':
        query = query.filter_by(ischeckedout=False)
    elif request.args.get('checkedout', '').lower() == 'true':
        query = query.filter_by(ischeckedout=True)

    # Search filter
    if search := request.args.get('search'):
        query = query.filter(
            db.or_(
                USBDevice.serialnumber.ilike(f'%{search}%'),
                USBDevice.label.ilike(f'%{search}%'),
                USBDevice.assetnumber.ilike(f'%{search}%'),
                USBDevice.manufacturer.ilike(f'%{search}%')
            )
        )

    query = query.order_by(USBDevice.label, USBDevice.serialnumber)

    items, total = paginate_query(query, page, per_page)
    data = [device.to_dict() for device in items]

    return paginated_response(data, page, per_page, total)


@usb_bp.route('', methods=['POST'])
@jwt_required()
def create_usb_device():
    """Create a new USB device."""
    data = request.get_json() or {}

    if not data.get('serialnumber'):
        return error_response(ErrorCodes.VALIDATION_ERROR, 'serialnumber is required')

    if USBDevice.query.filter_by(serialnumber=data['serialnumber']).first():
        return error_response(ErrorCodes.CONFLICT, 'Serial number already exists', http_code=409)

    device = USBDevice(
        serialnumber=data['serialnumber'],
        label=data.get('label'),
        assetnumber=data.get('assetnumber'),
        usbdevicetypeid=data.get('usbdevicetypeid'),
        capacitygb=data.get('capacitygb'),
        vendorid=data.get('vendorid'),
        productid=data.get('productid'),
        manufacturer=data.get('manufacturer'),
        productname=data.get('productname'),
        storagelocation=data.get('storagelocation'),
        pin=data.get('pin'),
        notes=data.get('notes'),
        ischeckedout=False
    )

    db.session.add(device)
    db.session.flush()

    AuditLog.log('created', 'USBDevice', entityid=device.usbdeviceid,
                 entityname=device.label or device.serialnumber)

    db.session.commit()

    return success_response(device.to_dict(), message='Device created', http_code=201)


@usb_bp.route('/<int:device_id>', methods=['GET'])
@jwt_required(optional=True)
def get_usb_device(device_id: int):
    """Get a single USB device with checkout history."""
    device = USBDevice.query.filter_by(usbdeviceid=device_id, isactive=True).first()

    if not device:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'USB device with ID {device_id} not found',
            http_code=404
        )

    # Get recent checkout history
    checkouts = USBCheckout.query.filter_by(
        usbdeviceid=device_id
    ).order_by(USBCheckout.checkouttime.desc()).limit(20).all()

    result = device.to_dict()
    result['checkouthistory'] = [c.to_dict() for c in checkouts]

    return success_response(result)


@usb_bp.route('/<int:device_id>', methods=['PUT'])
@jwt_required()
def update_usb_device(device_id: int):
    """Update a USB device."""
    device = USBDevice.query.filter_by(usbdeviceid=device_id, isactive=True).first()

    if not device:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'USB device with ID {device_id} not found',
            http_code=404
        )

    data = request.get_json() or {}

    # Track changes for audit log
    changes = {}
    for field in ['label', 'assetnumber', 'usbdevicetypeid', 'capacitygb',
                  'vendorid', 'productid', 'manufacturer', 'productname',
                  'storagelocation', 'pin', 'notes']:
        if field in data:
            old_val = getattr(device, field)
            new_val = data[field]
            if old_val != new_val:
                changes[field] = {'old': old_val, 'new': new_val}
            setattr(device, field, data[field])

    if changes:
        AuditLog.log('updated', 'USBDevice', entityid=device.usbdeviceid,
                     entityname=device.label or device.serialnumber, changes=changes)

    device.modifieddate = datetime.utcnow()
    db.session.commit()

    return success_response(device.to_dict(), message='Device updated')


@usb_bp.route('/<int:device_id>', methods=['DELETE'])
@jwt_required()
def delete_usb_device(device_id: int):
    """Soft delete a USB device."""
    device = USBDevice.query.filter_by(usbdeviceid=device_id, isactive=True).first()

    if not device:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'USB device with ID {device_id} not found',
            http_code=404
        )

    if device.ischeckedout:
        return error_response(
            ErrorCodes.VALIDATION_ERROR,
            'Cannot delete a device that is currently checked out',
            http_code=400
        )

    device.isactive = False
    device.modifieddate = datetime.utcnow()

    AuditLog.log('deleted', 'USBDevice', entityid=device.usbdeviceid,
                 entityname=device.label or device.serialnumber)

    db.session.commit()

    return success_response(None, message='Device deleted')


# =============================================================================
# Checkout/Checkin Operations
# =============================================================================

@usb_bp.route('/<int:device_id>/checkout', methods=['POST'])
@jwt_required()
def checkout_device(device_id: int):
    """Check out a USB device."""
    device = USBDevice.query.filter_by(usbdeviceid=device_id, isactive=True).first()

    if not device:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'USB device with ID {device_id} not found',
            http_code=404
        )

    if device.ischeckedout:
        return error_response(
            ErrorCodes.CONFLICT,
            f'Device is already checked out to {device.currentusername or device.currentuserid}',
            http_code=409
        )

    data = request.get_json() or {}

    if not data.get('sso'):
        return error_response(ErrorCodes.VALIDATION_ERROR, 'sso is required')

    # Create checkout record
    checkout = USBCheckout(
        usbdeviceid=device_id,
        machineid=0,  # Legacy field, set to 0 for new checkouts
        sso=data['sso'],
        checkoutname=data.get('checkoutname'),
        checkouttime=datetime.utcnow(),
        checkoutreason=data.get('checkoutreason'),
        waswiped=False
    )

    # Update device status
    device.ischeckedout = True
    device.currentuserid = data['sso']
    device.currentusername = data.get('checkoutname')
    device.currentcheckoutdate = datetime.utcnow()
    device.modifieddate = datetime.utcnow()

    db.session.add(checkout)

    AuditLog.log('checked_out', 'USBDevice', entityid=device.usbdeviceid,
                 entityname=device.label or device.serialnumber,
                 changes={'checked_out_to': data['sso'], 'reason': data.get('checkoutreason')})

    db.session.commit()

    return success_response(checkout.to_dict(), message='Device checked out', http_code=201)


@usb_bp.route('/<int:device_id>/checkin', methods=['POST'])
@jwt_required()
def checkin_device(device_id: int):
    """Check in a USB device."""
    device = USBDevice.query.filter_by(usbdeviceid=device_id, isactive=True).first()

    if not device:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'USB device with ID {device_id} not found',
            http_code=404
        )

    if not device.ischeckedout:
        return error_response(
            ErrorCodes.VALIDATION_ERROR,
            'Device is not currently checked out',
            http_code=400
        )

    # Find active checkout
    active_checkout = USBCheckout.query.filter_by(
        usbdeviceid=device_id,
        checkintime=None
    ).first()

    data = request.get_json() or {}

    if active_checkout:
        active_checkout.checkintime = datetime.utcnow()
        active_checkout.checkinnotes = data.get('checkinnotes', active_checkout.checkinnotes)
        active_checkout.waswiped = data.get('waswiped', False)

    # Update device status
    previous_user = device.currentuserid
    device.ischeckedout = False
    device.currentuserid = None
    device.currentusername = None
    device.currentcheckoutdate = None
    device.modifieddate = datetime.utcnow()

    AuditLog.log('checked_in', 'USBDevice', entityid=device.usbdeviceid,
                 entityname=device.label or device.serialnumber,
                 changes={'returned_by': previous_user, 'wiped': data.get('waswiped', False)})

    db.session.commit()

    return success_response(
        active_checkout.to_dict() if active_checkout else None,
        message='Device checked in'
    )


# =============================================================================
# Checkout History
# =============================================================================

@usb_bp.route('/<int:device_id>/history', methods=['GET'])
@jwt_required(optional=True)
def get_device_history(device_id: int):
    """Get checkout history for a USB device."""
    page, per_page = get_pagination_params(request)

    query = USBCheckout.query.filter_by(
        usbdeviceid=device_id
    ).order_by(USBCheckout.checkouttime.desc())

    items, total = paginate_query(query, page, per_page)
    data = [c.to_dict() for c in items]

    return paginated_response(data, page, per_page, total)


@usb_bp.route('/checkouts', methods=['GET'])
@jwt_required(optional=True)
def list_all_checkouts():
    """
    List all checkouts (active and historical).

    Query parameters:
    - active: Filter to only active (not returned) checkouts
    - sso: Filter by user SSO
    """
    page, per_page = get_pagination_params(request)

    query = USBCheckout.query

    # Filter by active only
    if request.args.get('active', '').lower() == 'true':
        query = query.filter(USBCheckout.checkintime == None)

    # Filter by user
    if sso := request.args.get('sso'):
        query = query.filter(USBCheckout.sso == sso)

    query = query.order_by(USBCheckout.checkouttime.desc())

    items, total = paginate_query(query, page, per_page)
    data = [c.to_dict() for c in items]

    return paginated_response(data, page, per_page, total)


@usb_bp.route('/checkouts/active', methods=['GET'])
@jwt_required(optional=True)
def list_active_checkouts():
    """List all currently active checkouts."""
    checkouts = USBCheckout.query.filter(
        USBCheckout.checkintime == None
    ).order_by(USBCheckout.checkouttime.desc()).all()

    return success_response([c.to_dict() for c in checkouts])
