"""Equipment plugin API endpoints."""

from flask import Blueprint, request
from flask_jwt_extended import jwt_required

from shopdb.extensions import db
from shopdb.core.models import Asset, AssetType, Vendor, Model, 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 Equipment, EquipmentType

equipment_bp = Blueprint('equipment', __name__)


# =============================================================================
# Equipment Types
# =============================================================================

@equipment_bp.route('/types', methods=['GET'])
@jwt_required(optional=True)
def list_equipment_types():
    """List all equipment types."""
    page, per_page = get_pagination_params(request)

    query = EquipmentType.query

    if request.args.get('active', 'true').lower() != 'false':
        query = query.filter(EquipmentType.isactive == True)

    if search := request.args.get('search'):
        query = query.filter(EquipmentType.equipmenttype.ilike(f'%{search}%'))

    query = query.order_by(EquipmentType.equipmenttype)

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

    return paginated_response(data, page, per_page, total)


@equipment_bp.route('/types/<int:type_id>', methods=['GET'])
@jwt_required(optional=True)
def get_equipment_type(type_id: int):
    """Get a single equipment type."""
    t = EquipmentType.query.get(type_id)

    if not t:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'Equipment type with ID {type_id} not found',
            http_code=404
        )

    return success_response(t.to_dict())


@equipment_bp.route('/types', methods=['POST'])
@jwt_required()
def create_equipment_type():
    """Create a new equipment type."""
    data = request.get_json()

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

    if EquipmentType.query.filter_by(equipmenttype=data['equipmenttype']).first():
        return error_response(
            ErrorCodes.CONFLICT,
            f"Equipment type '{data['equipmenttype']}' already exists",
            http_code=409
        )

    t = EquipmentType(
        equipmenttype=data['equipmenttype'],
        description=data.get('description'),
        icon=data.get('icon')
    )

    db.session.add(t)
    db.session.commit()

    return success_response(t.to_dict(), message='Equipment type created', http_code=201)


@equipment_bp.route('/types/<int:type_id>', methods=['PUT'])
@jwt_required()
def update_equipment_type(type_id: int):
    """Update an equipment type."""
    t = EquipmentType.query.get(type_id)

    if not t:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'Equipment type with ID {type_id} not found',
            http_code=404
        )

    data = request.get_json()
    if not data:
        return error_response(ErrorCodes.VALIDATION_ERROR, 'No data provided')

    if 'equipmenttype' in data and data['equipmenttype'] != t.equipmenttype:
        if EquipmentType.query.filter_by(equipmenttype=data['equipmenttype']).first():
            return error_response(
                ErrorCodes.CONFLICT,
                f"Equipment type '{data['equipmenttype']}' already exists",
                http_code=409
            )

    for key in ['equipmenttype', 'description', 'icon', 'isactive']:
        if key in data:
            setattr(t, key, data[key])

    db.session.commit()
    return success_response(t.to_dict(), message='Equipment type updated')


# =============================================================================
# Equipment CRUD
# =============================================================================

@equipment_bp.route('', methods=['GET'])
@jwt_required(optional=True)
def list_equipment():
    """
    List all equipment with filtering and pagination.

    Query parameters:
    - page, per_page: Pagination
    - active: Filter by active status
    - search: Search by asset number or name
    - type_id: Filter by equipment type ID
    - vendor_id: Filter by vendor ID
    - location_id: Filter by location ID
    - businessunit_id: Filter by business unit ID
    """
    page, per_page = get_pagination_params(request)

    # Join Equipment with Asset
    query = db.session.query(Equipment).join(Asset)

    # Active filter
    if request.args.get('active', 'true').lower() != 'false':
        query = query.filter(Asset.isactive == True)

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

    # Equipment type filter
    if type_id := request.args.get('type_id'):
        query = query.filter(Equipment.equipmenttypeid == int(type_id))

    # Vendor filter
    if vendor_id := request.args.get('vendor_id'):
        query = query.filter(Equipment.vendorid == int(vendor_id))

    # Location filter
    if location_id := request.args.get('location_id'):
        query = query.filter(Asset.locationid == int(location_id))

    # Business unit filter
    if bu_id := request.args.get('businessunit_id'):
        query = query.filter(Asset.businessunitid == int(bu_id))

    # Sorting
    sort_by = request.args.get('sort', 'assetnumber')
    sort_dir = request.args.get('dir', 'asc')

    if sort_by == 'assetnumber':
        col = Asset.assetnumber
    elif sort_by == 'name':
        col = Asset.name
    else:
        col = Asset.assetnumber

    query = query.order_by(col.desc() if sort_dir == 'desc' else col)

    items, total = paginate_query(query, page, per_page)

    # Build response with both asset and equipment data
    data = []
    for equip in items:
        item = equip.asset.to_dict() if equip.asset else {}
        item['equipment'] = equip.to_dict()
        data.append(item)

    return paginated_response(data, page, per_page, total)


@equipment_bp.route('/<int:equipment_id>', methods=['GET'])
@jwt_required(optional=True)
def get_equipment(equipment_id: int):
    """Get a single equipment item with full details."""
    equip = Equipment.query.get(equipment_id)

    if not equip:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'Equipment with ID {equipment_id} not found',
            http_code=404
        )

    result = equip.asset.to_dict() if equip.asset else {}
    result['equipment'] = equip.to_dict()

    return success_response(result)


@equipment_bp.route('/by-asset/<int:asset_id>', methods=['GET'])
@jwt_required(optional=True)
def get_equipment_by_asset(asset_id: int):
    """Get equipment data by asset ID."""
    equip = Equipment.query.filter_by(assetid=asset_id).first()

    if not equip:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'Equipment for asset {asset_id} not found',
            http_code=404
        )

    result = equip.asset.to_dict() if equip.asset else {}
    result['equipment'] = equip.to_dict()

    return success_response(result)


@equipment_bp.route('', methods=['POST'])
@jwt_required()
def create_equipment():
    """
    Create new equipment (creates both Asset and Equipment records).

    Required fields:
    - assetnumber: Business identifier

    Optional fields:
    - name, serialnumber, statusid, locationid, businessunitid
    - equipmenttypeid, vendorid, modelnumberid
    - requiresmanualconfig, islocationonly
    - mapx, mapy, notes
    """
    data = request.get_json()

    if not data:
        return error_response(ErrorCodes.VALIDATION_ERROR, 'No data provided')

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

    # Check for duplicate assetnumber
    if Asset.query.filter_by(assetnumber=data['assetnumber']).first():
        return error_response(
            ErrorCodes.CONFLICT,
            f"Asset with number '{data['assetnumber']}' already exists",
            http_code=409
        )

    # Get equipment asset type
    equipment_type = AssetType.query.filter_by(assettype='equipment').first()
    if not equipment_type:
        return error_response(
            ErrorCodes.INTERNAL_ERROR,
            'Equipment asset type not found. Plugin may not be properly installed.',
            http_code=500
        )

    # Create the core asset
    asset = Asset(
        assetnumber=data['assetnumber'],
        name=data.get('name'),
        serialnumber=data.get('serialnumber'),
        assettypeid=equipment_type.assettypeid,
        statusid=data.get('statusid', 1),
        locationid=data.get('locationid'),
        businessunitid=data.get('businessunitid'),
        mapx=data.get('mapx'),
        mapy=data.get('mapy'),
        notes=data.get('notes')
    )

    db.session.add(asset)
    db.session.flush()  # Get the assetid

    # Create the equipment extension
    equip = Equipment(
        assetid=asset.assetid,
        equipmenttypeid=data.get('equipmenttypeid'),
        vendorid=data.get('vendorid'),
        modelnumberid=data.get('modelnumberid'),
        requiresmanualconfig=data.get('requiresmanualconfig', False),
        islocationonly=data.get('islocationonly', False),
        lastmaintenancedate=data.get('lastmaintenancedate'),
        nextmaintenancedate=data.get('nextmaintenancedate'),
        maintenanceintervaldays=data.get('maintenanceintervaldays'),
        controllervendorid=data.get('controllervendorid'),
        controllermodelid=data.get('controllermodelid')
    )

    db.session.add(equip)
    db.session.flush()

    # Audit log
    AuditLog.log('created', 'Equipment', entityid=equip.equipmentid,
                 entityname=data['assetnumber'])

    db.session.commit()

    result = asset.to_dict()
    result['equipment'] = equip.to_dict()

    return success_response(result, message='Equipment created', http_code=201)


@equipment_bp.route('/<int:equipment_id>', methods=['PUT'])
@jwt_required()
def update_equipment(equipment_id: int):
    """Update equipment (both Asset and Equipment records)."""
    equip = Equipment.query.get(equipment_id)

    if not equip:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'Equipment with ID {equipment_id} not found',
            http_code=404
        )

    data = request.get_json()
    if not data:
        return error_response(ErrorCodes.VALIDATION_ERROR, 'No data provided')

    asset = equip.asset

    # Check for conflicting assetnumber
    if 'assetnumber' in data and data['assetnumber'] != asset.assetnumber:
        if Asset.query.filter_by(assetnumber=data['assetnumber']).first():
            return error_response(
                ErrorCodes.CONFLICT,
                f"Asset with number '{data['assetnumber']}' already exists",
                http_code=409
            )

    # Track changes for audit log
    changes = {}

    # Update asset fields
    asset_fields = ['assetnumber', 'name', 'serialnumber', 'statusid',
                    'locationid', 'businessunitid', 'mapx', 'mapy', 'notes', 'isactive']
    for key in asset_fields:
        if key in data:
            old_val = getattr(asset, key)
            new_val = data[key]
            if old_val != new_val:
                changes[key] = {'old': old_val, 'new': new_val}
            setattr(asset, key, data[key])

    # Update equipment fields
    equipment_fields = ['equipmenttypeid', 'vendorid', 'modelnumberid',
                        'requiresmanualconfig', 'islocationonly',
                        'lastmaintenancedate', 'nextmaintenancedate', 'maintenanceintervaldays',
                        'controllervendorid', 'controllermodelid']
    for key in equipment_fields:
        if key in data:
            old_val = getattr(equip, key)
            new_val = data[key]
            if old_val != new_val:
                changes[key] = {'old': old_val, 'new': new_val}
            setattr(equip, key, data[key])

    # Audit log if there were changes
    if changes:
        AuditLog.log('updated', 'Equipment', entityid=equip.equipmentid,
                     entityname=asset.assetnumber, changes=changes)

    db.session.commit()

    result = asset.to_dict()
    result['equipment'] = equip.to_dict()

    return success_response(result, message='Equipment updated')


@equipment_bp.route('/<int:equipment_id>', methods=['DELETE'])
@jwt_required()
def delete_equipment(equipment_id: int):
    """Delete (soft delete) equipment."""
    equip = Equipment.query.get(equipment_id)

    if not equip:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'Equipment with ID {equipment_id} not found',
            http_code=404
        )

    # Soft delete the asset (equipment extension will stay linked)
    equip.asset.isactive = False

    # Audit log
    AuditLog.log('deleted', 'Equipment', entityid=equip.equipmentid,
                 entityname=equip.asset.assetnumber)

    db.session.commit()

    return success_response(message='Equipment deleted')


# =============================================================================
# Dashboard
# =============================================================================

@equipment_bp.route('/dashboard/summary', methods=['GET'])
@jwt_required(optional=True)
def dashboard_summary():
    """Get equipment dashboard summary data."""
    # Total active equipment count
    total = db.session.query(Equipment).join(Asset).filter(
        Asset.isactive == True
    ).count()

    # Count by equipment type
    by_type = db.session.query(
        EquipmentType.equipmenttype,
        db.func.count(Equipment.equipmentid)
    ).join(Equipment, Equipment.equipmenttypeid == EquipmentType.equipmenttypeid
    ).join(Asset, Asset.assetid == Equipment.assetid
    ).filter(Asset.isactive == True
    ).group_by(EquipmentType.equipmenttype
    ).all()

    # Count by status
    from shopdb.core.models import AssetStatus
    by_status = db.session.query(
        AssetStatus.status,
        db.func.count(Equipment.equipmentid)
    ).join(Asset, Asset.assetid == Equipment.assetid
    ).join(AssetStatus, AssetStatus.statusid == Asset.statusid
    ).filter(Asset.isactive == True
    ).group_by(AssetStatus.status
    ).all()

    return success_response({
        'total': total,
        'bytype': [{'type': t, 'count': c} for t, c in by_type],
        'bystatus': [{'status': s, 'count': c} for s, c in by_status]
    })
