import logging
from typing import List, Optional
from fastapi import APIRouter, HTTPException, Query, UploadFile, File
from app.core.database import execute_query
from app.services.eset_service import eset_service
from psycopg2.extras import Json
from datetime import datetime, date
import os
import uuid

logger = logging.getLogger(__name__)
router = APIRouter()


def _eset_extract_first_str(payload: dict, keys: List[str]) -> Optional[str]:
    if payload is None:
        return None

    key_set = {k.lower() for k in keys}
    stack = [payload]
    while stack:
        current = stack.pop()
        if isinstance(current, dict):
            for k, v in current.items():
                if k.lower() in key_set and isinstance(v, str) and v.strip():
                    return v.strip()
                if isinstance(v, (dict, list)):
                    stack.append(v)
        elif isinstance(current, list):
            for item in current:
                if isinstance(item, (dict, list)):
                    stack.append(item)
    return None


def _eset_extract_group_path(payload: dict) -> Optional[str]:
    return _eset_extract_first_str(payload, ["parentGroup", "groupPath", "group", "path"])


def _eset_extract_group_name(payload: dict) -> Optional[str]:
    group_path = _eset_extract_group_path(payload)
    if group_path and "/" in group_path:
        name = group_path.split("/")[-1].strip()
        return name or None
    return group_path


def _eset_extract_company(payload: dict) -> Optional[str]:
    company = _eset_extract_first_str(payload, ["company", "organization", "tenant", "customer", "userCompany"])
    if company:
        return company
    group_path = _eset_extract_group_path(payload)
    if group_path and "/" in group_path:
        return group_path.split("/")[-1].strip() or None
    return None


def _eset_extract_login_candidates(payload: dict) -> List[str]:
    raw = _eset_extract_first_str(
        payload,
        ["userPrincipalName", "upn", "email", "mail", "loginName", "login", "userName", "lastLoggedInUser"]
    )
    if not raw:
        return []

    candidates: List[str] = []

    def _add(value: str) -> None:
        v = (value or "").strip().lower()
        if v and v not in candidates:
            candidates.append(v)

    _add(raw)
    if "\\" in raw:
        _add(raw.split("\\")[-1])
    if "/" in raw:
        _add(raw.split("/")[-1])
    if "@" in raw:
        _add(raw.split("@", 1)[0])

    return candidates


def _match_contact_by_login(login_candidate: str, company: Optional[str] = None) -> Optional[int]:
    if not login_candidate:
        return None

    if company:
        scoped = execute_query(
            """
                SELECT id
                FROM contacts
                WHERE LOWER(COALESCE(email, '')) = LOWER(%s)
                  AND LOWER(COALESCE(user_company, '')) = LOWER(%s)
                LIMIT 1
            """,
            (login_candidate, company),
        )
        if scoped:
            return scoped[0]["id"]

        scoped_local_part = execute_query(
            """
                SELECT id
                FROM contacts
                WHERE LOWER(split_part(COALESCE(email, ''), '@', 1)) = LOWER(%s)
                  AND LOWER(COALESCE(user_company, '')) = LOWER(%s)
                LIMIT 1
            """,
            (login_candidate, company),
        )
        if scoped_local_part:
            return scoped_local_part[0]["id"]

    by_email = execute_query(
        """
            SELECT id
            FROM contacts
            WHERE LOWER(COALESCE(email, '')) = LOWER(%s)
            LIMIT 1
        """,
        (login_candidate,),
    )
    if by_email:
        return by_email[0]["id"]

    by_local_part = execute_query(
        """
            SELECT id
            FROM contacts
            WHERE LOWER(split_part(COALESCE(email, ''), '@', 1)) = LOWER(%s)
            LIMIT 1
        """,
        (login_candidate,),
    )
    if by_local_part:
        return by_local_part[0]["id"]

    return None


def _eset_detect_asset_type(payload: dict) -> str:
    device_type = _eset_extract_first_str(payload, ["deviceType", "type"])
    if device_type:
        val = device_type.lower()
        if "server" in val:
            return "server"
        if "laptop" in val or "notebook" in val:
            return "laptop"
    return "pc"


def _match_customer_exact(name: str) -> Optional[int]:
    if not name:
        return None
    result = execute_query("SELECT id FROM customers WHERE LOWER(name) = LOWER(%s)", (name,))
    if len(result or []) == 1:
        return result[0]["id"]
    return None


def _get_contact_customer(contact_id: int) -> Optional[int]:
    query = """
        SELECT customer_id
        FROM contact_companies
        WHERE contact_id = %s
        ORDER BY is_primary DESC, id ASC
        LIMIT 1
    """
    result = execute_query(query, (contact_id,))
    if result:
        return result[0]["customer_id"]
    return None


def _match_contact_by_name_and_company(full_name: str, company: str) -> Optional[int]:
    if not full_name or not company:
        return None

    query = """
        SELECT id
        FROM contacts
        WHERE LOWER(TRIM(first_name || ' ' || last_name)) = LOWER(%s)
          AND LOWER(COALESCE(user_company, '')) = LOWER(%s)
        LIMIT 1
    """
    result = execute_query(query, (full_name, company))
    if result:
        return result[0]["id"]
    return None


def _upsert_hardware_contact(hardware_id: int, contact_id: int) -> None:
    query = """
        INSERT INTO hardware_contacts (hardware_id, contact_id, role, source)
        VALUES (%s, %s, %s, %s)
        ON CONFLICT (hardware_id, contact_id) DO NOTHING
    """
    execute_query(query, (hardware_id, contact_id, "primary", "eset"))

# ============================================================================
# CRUD Endpoints for Hardware Assets
# ============================================================================

@router.get("/hardware", response_model=List[dict])
async def list_hardware(
    customer_id: Optional[int] = None,
    status: Optional[str] = None,
    asset_type: Optional[str] = None,
    q: Optional[str] = None
):
    """List all hardware with optional filters."""
    query = "SELECT * FROM hardware_assets WHERE deleted_at IS NULL"
    params = []

    if customer_id:
        query += " AND current_owner_customer_id = %s"
        params.append(customer_id)
    if status:
        query += " AND status = %s"
        params.append(status)
    if asset_type:
        query += " AND asset_type = %s"
        params.append(asset_type)
    if q:
        query += " AND (serial_number ILIKE %s OR model ILIKE %s OR brand ILIKE %s)"
        search_param = f"%{q}%"
        params.extend([search_param, search_param, search_param])

    query += " ORDER BY created_at DESC"
    
    result = execute_query(query, tuple(params))
    logger.info(f"✅ Listed {len(result) if result else 0} hardware assets")
    return result or []


@router.get("/hardware/by-customer/{customer_id}", response_model=List[dict])
async def list_hardware_by_customer(customer_id: int):
    """List hardware assets owned by a customer."""
    query = """
        SELECT * FROM hardware_assets
        WHERE deleted_at IS NULL AND current_owner_customer_id = %s
        ORDER BY created_at DESC
    """
    result = execute_query(query, (customer_id,))
    return result or []


@router.get("/hardware/by-contact/{contact_id}", response_model=List[dict])
async def list_hardware_by_contact(contact_id: int):
    """
    List hardware assets linked directly to a contact.
    Supports both hardware_assets (new) and hardware (legacy) tables.
    """
    # Try new hardware_assets table via hardware_contacts
    query_new = """
        SELECT DISTINCT 
            h.id,
            h.asset_type,
            h.brand,
            h.model,
            h.serial_number,
            h.anydesk_id,
            h.anydesk_link,
            h.status,
            h.notes,
            h.created_at,
            'hardware_assets' as source_table
        FROM hardware_assets h
        JOIN hardware_contacts hc ON hc.hardware_id = h.id
        WHERE hc.contact_id = %s AND h.deleted_at IS NULL
        ORDER BY h.created_at DESC
    """
    result_new = execute_query(query_new, (contact_id,))
    
    # Also look up hardware_assets by the contact's company (customer link)
    query_by_customer = """
        SELECT DISTINCT
            h.id,
            h.asset_type,
            h.brand,
            h.model,
            h.serial_number,
            h.anydesk_id,
            h.anydesk_link,
            h.status,
            h.notes,
            h.created_at,
            'hardware_assets' as source_table
        FROM hardware_assets h
        WHERE h.current_owner_customer_id IN (
            SELECT customer_id
            FROM contact_companies
            WHERE contact_id = %s
        )
        AND h.deleted_at IS NULL
        ORDER BY h.created_at DESC
    """
    result_customer = execute_query(query_by_customer, (contact_id,))

    # Merge: hardware_contacts first (direct link), then customer-linked, dedup by id
    seen = set()
    all_results = []
    for item in (result_new or []) + (result_customer or []):
        if item["id"] not in seen:
            seen.add(item["id"])
            all_results.append(item)

    return all_results


@router.get("/hardware/unassigned", response_model=List[dict])
async def list_unassigned_hardware(limit: int = 200):
    """List hardware assets not linked to any contact."""
    query = """
        SELECT h.id, h.asset_type, h.brand, h.model, h.serial_number, h.status
        FROM hardware_assets h
        WHERE h.deleted_at IS NULL
          AND NOT EXISTS (
              SELECT 1 FROM hardware_contacts hc WHERE hc.hardware_id = h.id
          )
        ORDER BY h.created_at DESC
        LIMIT %s
    """
    result = execute_query(query, (limit,))
    return result or []


@router.post("/hardware/{hardware_id}/assign-contact", response_model=dict)
async def assign_hardware_to_contact(hardware_id: int, payload: dict):
    """Link hardware asset to a contact."""
    contact_id = payload.get("contact_id")
    if not contact_id:
        raise HTTPException(status_code=422, detail="contact_id is required")

    hardware = execute_query("SELECT id FROM hardware_assets WHERE id = %s AND deleted_at IS NULL", (hardware_id,))
    if not hardware:
        raise HTTPException(status_code=404, detail="Hardware not found")

    contact = execute_query("SELECT id FROM contacts WHERE id = %s", (contact_id,))
    if not contact:
        raise HTTPException(status_code=404, detail="Contact not found")

    execute_query(
        """
        INSERT INTO hardware_contacts (hardware_id, contact_id, role, source)
        VALUES (%s, %s, %s, %s)
        ON CONFLICT (hardware_id, contact_id) DO NOTHING
        """,
        (hardware_id, contact_id, "primary", "manual"),
    )

    customer_id = _get_contact_customer(int(contact_id))
    if customer_id:
        execute_query(
            """
            UPDATE hardware_assets
            SET current_owner_customer_id = COALESCE(current_owner_customer_id, %s)
            WHERE id = %s
            """,
            (customer_id, hardware_id),
        )

    return {"status": "ok"}


@router.post("/hardware", response_model=dict)
async def create_hardware(data: dict):
    """Create a new hardware asset."""
    try:
        query = """
            INSERT INTO hardware_assets (
                asset_type, brand, model, serial_number, customer_asset_id, 
                internal_asset_id, notes, current_owner_type, current_owner_customer_id,
                status, status_reason, warranty_until, end_of_life,
                anydesk_id, anydesk_link,
                eset_uuid, hardware_specs, eset_group,
                rental_default_start_price, rental_default_freight_price,
                rental_default_preparation_price, rental_default_operations_monthly_price
            )
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
            RETURNING *
        """
        
        specs = data.get("hardware_specs")
        if specs:
            specs = Json(specs)
            
        params = (
            data.get("asset_type"),
            data.get("brand"),
            data.get("model"),
            data.get("serial_number"),
            data.get("customer_asset_id"),
            data.get("internal_asset_id"),
            data.get("notes"),
            data.get("current_owner_type", "bmc"),
            data.get("current_owner_customer_id"),
            data.get("status", "active"),
            data.get("status_reason"),
            data.get("warranty_until"),
            data.get("end_of_life"),
            data.get("anydesk_id"),
            data.get("anydesk_link"),
            data.get("eset_uuid"),
            specs,
            data.get("eset_group"),
            data.get("rental_default_start_price"),
            data.get("rental_default_freight_price"),
            data.get("rental_default_preparation_price"),
            data.get("rental_default_operations_monthly_price"),
        )
        result = execute_query(query, params)
        if not result:
            raise HTTPException(status_code=500, detail="Failed to create hardware")
        
        hardware = result[0]
        logger.info(f"✅ Created hardware asset: {hardware['id']} - {hardware['brand']} {hardware['model']}")
        
        # Create initial ownership record if owner specified
        if data.get("current_owner_type"):
            ownership_query = """
                INSERT INTO hardware_ownership_history (
                    hardware_id, owner_type, owner_customer_id, start_date, notes
                )
                VALUES (%s, %s, %s, %s, %s)
            """
            ownership_params = (
                hardware['id'],
                data.get("current_owner_type"),
                data.get("current_owner_customer_id"),
                date.today(),
                "Initial ownership record"
            )
            execute_query(ownership_query, ownership_params)
        
        return hardware
    except Exception as e:
        logger.error(f"❌ Failed to create hardware: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/hardware/quick", response_model=dict)
async def quick_create_hardware(data: dict):
    """Quick create hardware with minimal fields (name + AnyDesk info)."""
    try:
        name = (data.get("name") or "").strip()
        customer_id = data.get("customer_id")
        anydesk_id = (data.get("anydesk_id") or "").strip() or None
        anydesk_link = (data.get("anydesk_link") or "").strip() or None

        if not name:
            raise HTTPException(status_code=400, detail="Name is required")
        if not customer_id:
            raise HTTPException(status_code=400, detail="Customer ID is required")

        query = """
            INSERT INTO hardware_assets (
                asset_type, model, current_owner_type, current_owner_customer_id,
                status, anydesk_id, anydesk_link, notes
            )
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
            RETURNING *
        """
        params = (
            "andet",
            name,
            "customer",
            customer_id,
            "active",
            anydesk_id,
            anydesk_link,
            "Quick created from case/ticket flow",
        )
        result = execute_query(query, params)
        if not result:
            raise HTTPException(status_code=500, detail="Failed to create hardware")

        return result[0]
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"❌ Failed to quick-create hardware: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/hardware/{hardware_id}", response_model=dict)
async def get_hardware(hardware_id: int):
    """Get hardware details by ID."""
    query = "SELECT * FROM hardware_assets WHERE id = %s AND deleted_at IS NULL"
    result = execute_query(query, (hardware_id,))
    if not result:
        raise HTTPException(status_code=404, detail="Hardware not found")
    
    logger.info(f"✅ Retrieved hardware: {hardware_id}")
    return result[0]


@router.patch("/hardware/{hardware_id}", response_model=dict)
async def update_hardware(hardware_id: int, data: dict):
    """Update hardware asset."""
    try:
        # Build dynamic update query
        update_fields = []
        params = []
        
        allowed_fields = [
            "asset_type", "brand", "model", "serial_number", "customer_asset_id",
            "internal_asset_id", "notes", "current_owner_type", "current_owner_customer_id",
            "status", "status_reason", "warranty_until", "end_of_life",
            "follow_up_date", "follow_up_owner_user_id", "anydesk_id", "anydesk_link",
            "eset_uuid", "hardware_specs", "eset_group",
            "rental_default_start_price", "rental_default_freight_price",
            "rental_default_preparation_price", "rental_default_operations_monthly_price"
        ]
        
        for field in allowed_fields:
            if field in data:
                update_fields.append(f"{field} = %s")
                val = data[field]
                if field == "hardware_specs" and val:
                    val = Json(val)
                params.append(val)
        
        if not update_fields:
            raise HTTPException(status_code=400, detail="No valid fields to update")
        
        update_fields.append("updated_at = NOW()")
        params.append(hardware_id)
        
        query = f"""
            UPDATE hardware_assets 
            SET {', '.join(update_fields)}
            WHERE id = %s AND deleted_at IS NULL
            RETURNING *
        """
        
        result = execute_query(query, tuple(params))
        if not result:
            raise HTTPException(status_code=404, detail="Hardware not found")
        
        logger.info(f"✅ Updated hardware: {hardware_id}")
        return result[0]
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"❌ Failed to update hardware {hardware_id}: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/hardware/{hardware_id}")
async def delete_hardware(hardware_id: int):
    """Soft-delete hardware asset."""
    query = """
        UPDATE hardware_assets 
        SET deleted_at = NOW() 
        WHERE id = %s AND deleted_at IS NULL
        RETURNING id
    """
    result = execute_query(query, (hardware_id,))
    if not result:
        raise HTTPException(status_code=404, detail="Hardware not found")
    
    logger.info(f"✅ Deleted hardware: {hardware_id}")
    return {"message": "Hardware deleted successfully"}


# ============================================================================
# Ownership History Endpoints
# ============================================================================

@router.get("/hardware/{hardware_id}/ownership", response_model=List[dict])
async def get_ownership_history(hardware_id: int):
    """Get ownership history for hardware."""
    query = """
        SELECT * FROM hardware_ownership_history 
        WHERE hardware_id = %s AND deleted_at IS NULL
        ORDER BY start_date DESC
    """
    result = execute_query(query, (hardware_id,))
    logger.info(f"✅ Retrieved ownership history for hardware: {hardware_id}")
    return result or []


@router.post("/hardware/{hardware_id}/ownership", response_model=dict)
async def add_ownership_record(hardware_id: int, data: dict):
    """Add ownership record (auto-closes previous active ownership)."""
    try:
        # Close any active ownership records
        close_query = """
            UPDATE hardware_ownership_history 
            SET end_date = %s 
            WHERE hardware_id = %s AND end_date IS NULL AND deleted_at IS NULL
        """
        execute_query(close_query, (date.today(), hardware_id))
        
        # Create new ownership record
        insert_query = """
            INSERT INTO hardware_ownership_history (
                hardware_id, owner_type, owner_customer_id, start_date, notes
            )
            VALUES (%s, %s, %s, %s, %s)
            RETURNING *
        """
        params = (
            hardware_id,
            data.get("owner_type"),
            data.get("owner_customer_id"),
            data.get("start_date", date.today()),
            data.get("notes")
        )
        result = execute_query(insert_query, params)
        
        # Update current owner in hardware_assets
        update_query = """
            UPDATE hardware_assets 
            SET current_owner_type = %s, current_owner_customer_id = %s, updated_at = NOW()
            WHERE id = %s
        """
        execute_query(update_query, (data.get("owner_type"), data.get("owner_customer_id"), hardware_id))
        
        logger.info(f"✅ Added ownership record for hardware: {hardware_id}")
        return result[0]
    except Exception as e:
        logger.error(f"❌ Failed to add ownership record: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


# ============================================================================
# Location History Endpoints
# ============================================================================

@router.get("/hardware/{hardware_id}/locations", response_model=List[dict])
async def get_location_history(hardware_id: int):
    """Get location history for hardware."""
    query = """
        SELECT * FROM hardware_location_history 
        WHERE hardware_id = %s AND deleted_at IS NULL
        ORDER BY start_date DESC
    """
    result = execute_query(query, (hardware_id,))
    logger.info(f"✅ Retrieved location history for hardware: {hardware_id}")
    return result or []


@router.post("/hardware/{hardware_id}/locations", response_model=dict)
async def add_location_record(hardware_id: int, data: dict):
    """Add location record (auto-closes previous active location)."""
    try:
        # Close any active location records
        close_query = """
            UPDATE hardware_location_history 
            SET end_date = %s 
            WHERE hardware_id = %s AND end_date IS NULL AND deleted_at IS NULL
        """
        execute_query(close_query, (date.today(), hardware_id))
        
        # Create new location record
        insert_query = """
            INSERT INTO hardware_location_history (
                hardware_id, location_id, location_name, start_date, notes
            )
            VALUES (%s, %s, %s, %s, %s)
            RETURNING *
        """
        params = (
            hardware_id,
            data.get("location_id"),
            data.get("location_name"),
            data.get("start_date", date.today()),
            data.get("notes")
        )
        result = execute_query(insert_query, params)
        
        # Update current location in hardware_assets
        update_query = """
            UPDATE hardware_assets 
            SET current_location_id = %s, updated_at = NOW()
            WHERE id = %s
        """
        execute_query(update_query, (data.get("location_id"), hardware_id))
        
        logger.info(f"✅ Added location record for hardware: {hardware_id}")
        return result[0]
    except Exception as e:
        logger.error(f"❌ Failed to add location record: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


# ============================================================================
# Attachment Endpoints
# ============================================================================

@router.get("/hardware/{hardware_id}/attachments", response_model=List[dict])
async def get_attachments(hardware_id: int):
    """Get all attachments for hardware."""
    query = """
        SELECT * FROM hardware_attachments 
        WHERE hardware_id = %s AND deleted_at IS NULL
        ORDER BY uploaded_at DESC
    """
    result = execute_query(query, (hardware_id,))
    logger.info(f"✅ Retrieved {len(result) if result else 0} attachments for hardware: {hardware_id}")
    return result or []


@router.post("/hardware/{hardware_id}/attachments", response_model=dict)
async def upload_attachment(hardware_id: int, data: dict):
    """Upload attachment for hardware."""
    try:
        # Generate storage reference (in production, this would upload to cloud storage)
        storage_ref = f"hardware/{hardware_id}/{uuid.uuid4()}_{data.get('file_name')}"
        
        query = """
            INSERT INTO hardware_attachments (
                hardware_id, file_type, file_name, storage_ref, 
                file_size_bytes, mime_type, description, uploaded_by_user_id
            )
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
            RETURNING *
        """
        params = (
            hardware_id,
            data.get("file_type", "other"),
            data.get("file_name"),
            storage_ref,
            data.get("file_size_bytes"),
            data.get("mime_type"),
            data.get("description"),
            data.get("uploaded_by_user_id")
        )
        result = execute_query(query, params)
        
        logger.info(f"✅ Uploaded attachment for hardware: {hardware_id}")
        return result[0]
    except Exception as e:
        logger.error(f"❌ Failed to upload attachment: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/hardware/{hardware_id}/attachments/{attachment_id}")
async def delete_attachment(hardware_id: int, attachment_id: int):
    """Soft-delete attachment."""
    query = """
        UPDATE hardware_attachments 
        SET deleted_at = NOW() 
        WHERE id = %s AND hardware_id = %s AND deleted_at IS NULL
        RETURNING id
    """
    result = execute_query(query, (attachment_id, hardware_id))
    if not result:
        raise HTTPException(status_code=404, detail="Attachment not found")
    
    logger.info(f"✅ Deleted attachment {attachment_id} for hardware: {hardware_id}")
    return {"message": "Attachment deleted successfully"}


# ============================================================================
# Case Relations Endpoints
# ============================================================================

@router.get("/hardware/{hardware_id}/cases", response_model=List[dict])
async def get_related_cases(hardware_id: int):
    """Get all cases related to this hardware."""
    query = """
        SELECT hcr.*, s.titel, s.status, s.customer_id
        FROM hardware_case_relations hcr
        LEFT JOIN sag_sager s ON hcr.case_id = s.id
        WHERE hcr.hardware_id = %s AND hcr.deleted_at IS NULL AND s.deleted_at IS NULL
        ORDER BY hcr.created_at DESC
    """
    result = execute_query(query, (hardware_id,))
    logger.info(f"✅ Retrieved {len(result) if result else 0} related cases for hardware: {hardware_id}")
    return result or []


@router.post("/hardware/{hardware_id}/cases", response_model=dict)
async def link_case(hardware_id: int, data: dict):
    """Link hardware to a case."""
    try:
        query = """
            INSERT INTO hardware_case_relations (
                hardware_id, case_id, relation_type
            )
            VALUES (%s, %s, %s)
            RETURNING *
        """
        params = (
            hardware_id,
            data.get("case_id"),
            data.get("relation_type", "related")
        )
        result = execute_query(query, params)
        
        logger.info(f"✅ Linked hardware {hardware_id} to case {data.get('case_id')}")
        return result[0]
    except Exception as e:
        logger.error(f"❌ Failed to link case: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/hardware/{hardware_id}/cases/{case_id}")
async def unlink_case(hardware_id: int, case_id: int):
    """Unlink hardware from a case."""
    query = """
        UPDATE hardware_case_relations 
        SET deleted_at = NOW() 
        WHERE hardware_id = %s AND case_id = %s AND deleted_at IS NULL
        RETURNING id
    """
    result = execute_query(query, (hardware_id, case_id))
    if not result:
        raise HTTPException(status_code=404, detail="Case relation not found")
    
    logger.info(f"✅ Unlinked hardware {hardware_id} from case {case_id}")
    return {"message": "Case unlinked successfully"}


# ============================================================================
# Tag Endpoints
# ============================================================================

@router.get("/hardware/{hardware_id}/tags", response_model=List[dict])
async def get_tags(hardware_id: int):
    """Get all tags for hardware."""
    query = """
        SELECT * FROM hardware_tags 
        WHERE hardware_id = %s AND deleted_at IS NULL
        ORDER BY created_at DESC
    """
    result = execute_query(query, (hardware_id,))
    logger.info(f"✅ Retrieved {len(result) if result else 0} tags for hardware: {hardware_id}")
    return result or []


@router.post("/hardware/{hardware_id}/tags", response_model=dict)
async def add_tag(hardware_id: int, data: dict):
    """Add tag to hardware."""
    try:
        query = """
            INSERT INTO hardware_tags (
                hardware_id, tag_name, tag_type
            )
            VALUES (%s, %s, %s)
            RETURNING *
        """
        params = (
            hardware_id,
            data.get("tag_name"),
            data.get("tag_type", "manual")
        )
        result = execute_query(query, params)
        
        logger.info(f"✅ Added tag '{data.get('tag_name')}' to hardware: {hardware_id}")
        return result[0]
    except Exception as e:
        logger.error(f"❌ Failed to add tag: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/hardware/{hardware_id}/tags/{tag_id}")
async def delete_tag(hardware_id: int, tag_id: int):
    """Delete tag from hardware."""
    query = """
        UPDATE hardware_tags 
        SET deleted_at = NOW() 
        WHERE id = %s AND hardware_id = %s AND deleted_at IS NULL
        RETURNING id
    """
    result = execute_query(query, (tag_id, hardware_id))
    if not result:
        raise HTTPException(status_code=404, detail="Tag not found")
    
    logger.info(f"✅ Deleted tag {tag_id} from hardware: {hardware_id}")
    return {"message": "Tag deleted successfully"}


# ============================================================================
# Search Endpoint
# ============================================================================

@router.get("/search/hardware", response_model=List[dict])
async def search_hardware(q: str = Query(..., min_length=1)):
    """Search hardware by serial number, model, or brand."""
    query = """
        SELECT * FROM hardware_assets 
        WHERE deleted_at IS NULL
        AND (
            serial_number ILIKE %s 
            OR model ILIKE %s 
            OR brand ILIKE %s
            OR customer_asset_id ILIKE %s
            OR internal_asset_id ILIKE %s
        )
        ORDER BY created_at DESC
        LIMIT 50
    """
    search_param = f"%{q}%"
    result = execute_query(query, (search_param, search_param, search_param, search_param, search_param))
    
    logger.info(f"✅ Search for '{q}' returned {len(result) if result else 0} results")
    return result or []


@router.post("/hardware/{hardware_id}/sync-eset", response_model=dict)
async def sync_eset_data(hardware_id: int, eset_uuid: Optional[str] = Query(None)):
    """Sync hardware data from ESET."""
    # Get current hardware
    check_query = "SELECT * FROM hardware_assets WHERE id = %s AND deleted_at IS NULL"
    result = execute_query(check_query, (hardware_id,))
    if not result:
        raise HTTPException(status_code=404, detail="Hardware not found")
    current = result[0]
    
    # Determine UUID
    uuid_to_use = eset_uuid or current.get("eset_uuid")
    if not uuid_to_use:
        raise HTTPException(status_code=400, detail="No ESET UUID provided or found on asset. Please provide 'eset_uuid' query parameter.")
        
    # Fetch from ESET
    details = await eset_service.get_device_details(uuid_to_use)
    if not details:
        raise HTTPException(status_code=404, detail="Device not found in ESET")
        
    # Update hardware asset
    update_data = {
        "eset_uuid": uuid_to_use,
        "hardware_specs": details
    }
    
    # We can perform the update directly here or call update_hardware if available
    return await update_hardware(hardware_id, update_data)


@router.get("/hardware/eset/test", response_model=dict)
async def test_eset_device(device_uuid: str = Query(..., min_length=1)):
    """Test ESET device lookup by UUID."""
    details = await eset_service.get_device_details(device_uuid)
    if not details:
        raise HTTPException(status_code=404, detail="Device not found in ESET")

    return details


@router.get("/hardware/eset/test-one-pc-full", response_model=dict)
async def test_eset_one_pc_full(include_raw: bool = Query(False)):
    """Fetch one device from ESET and return full parsed test payload including software list."""
    payload = await eset_service.list_devices(page_size=1)
    if not payload:
        raise HTTPException(status_code=404, detail="No devices returned from ESET")

    devices = payload.get("devices") or payload.get("items") or payload.get("results") or payload.get("data") or []
    if not devices:
        raise HTTPException(status_code=404, detail="No devices found in ESET list")

    first_device = devices[0]
    device_uuid = (
        first_device.get("deviceUuid")
        or first_device.get("uuid")
        or first_device.get("id")
        or ""
    )
    if not device_uuid:
        raise HTTPException(status_code=404, detail="No device UUID found on first ESET device")

    details = await eset_service.get_device_details(device_uuid)
    if not details:
        raise HTTPException(status_code=404, detail="Device details not found in ESET")

    software = eset_service.extract_installed_software(details)
    identifier_fields = [
        "userPrincipalName", "upn", "email", "mail", "loginName", "login", "userName", "lastLoggedInUser", "owner", "ownerUuid"
    ]
    identifier_candidates = []
    for field_name in identifier_fields:
        value = _eset_extract_first_str(details, [field_name])
        if value and value not in identifier_candidates:
            identifier_candidates.append(value)

    user_identifier = identifier_candidates[0] if identifier_candidates else None

    response = {
        "device_uuid": device_uuid,
        "device_name": _eset_extract_first_str(details, ["displayName", "deviceName", "name"]),
        "user_identifier": user_identifier,
        "group": _eset_extract_group_path(details),
        "serial": _eset_extract_first_str(details, ["serialNumber", "serial", "serial_number"]),
        "identifier_candidates": identifier_candidates,
        "installed_software_count": len(software),
        "installed_software": software,
    }

    if include_raw:
        response["raw"] = details

    return response


@router.get("/hardware/eset/devices", response_model=dict)
async def list_eset_devices(
    page_size: Optional[int] = Query(None, ge=1, le=1000),
    page_token: Optional[str] = Query(None)
):
    """List devices directly from ESET Device Management."""
    payload = await eset_service.list_devices(page_size=page_size, page_token=page_token)
    if not payload:
        raise HTTPException(status_code=404, detail="No devices returned from ESET")
    return payload


@router.post("/hardware/eset/import", response_model=dict)
async def import_eset_device(data: dict):
    """Import ESET device into hardware assets and optionally link to contact."""
    device_uuid = (data.get("device_uuid") or "").strip()
    contact_id = data.get("contact_id")

    if not device_uuid:
        raise HTTPException(status_code=400, detail="device_uuid is required")

    details = await eset_service.get_device_details(device_uuid)
    if not details:
        raise HTTPException(status_code=404, detail="Device not found in ESET")

    serial = _eset_extract_first_str(details, ["serialNumber", "serial", "serial_number"])
    model = _eset_extract_first_str(details, ["model", "deviceModel", "deviceName", "name"])
    brand = _eset_extract_first_str(details, ["manufacturer", "brand", "vendor"])
    group_path = _eset_extract_group_path(details)
    group_name = _eset_extract_group_name(details)
    company = _eset_extract_company(details)
    login_candidates = _eset_extract_login_candidates(details)
    full_name = _eset_extract_first_str(details, ["realName", "displayName", "userName", "owner", "user", "lastLoggedInUser"])

    if contact_id:
        contact_check = execute_query("SELECT id FROM contacts WHERE id = %s", (contact_id,))
        if not contact_check:
            raise HTTPException(status_code=404, detail="Contact not found")

    if not contact_id:
        contact_id = _match_contact_by_name_and_company(full_name, company)
    if not contact_id:
        for login_candidate in login_candidates:
            contact_id = _match_contact_by_login(login_candidate, company)
            if contact_id:
                break

    customer_id = _get_contact_customer(contact_id) if contact_id else None
    if not customer_id:
        customer_id = _match_customer_exact(group_name or company)

    owner_type = "customer" if customer_id else "bmc"

    conditions = ["eset_uuid = %s"]
    params = [device_uuid]
    if serial:
        conditions.append("serial_number = %s")
        params.append(serial)

    lookup_query = f"SELECT * FROM hardware_assets WHERE deleted_at IS NULL AND ({' OR '.join(conditions)})"
    existing = execute_query(lookup_query, tuple(params))

    if existing:
        hardware_id = existing[0]["id"]
        update_fields = ["eset_uuid = %s", "hardware_specs = %s", "updated_at = NOW()"]
        update_params = [device_uuid, Json(details)]

        if group_path:
            update_fields.append("eset_group = %s")
            update_params.append(group_path)
        if not existing[0].get("serial_number") and serial:
            update_fields.append("serial_number = %s")
            update_params.append(serial)
        if not existing[0].get("model") and model:
            update_fields.append("model = %s")
            update_params.append(model)
        if not existing[0].get("brand") and brand:
            update_fields.append("brand = %s")
            update_params.append(brand)
        if customer_id:
            update_fields.append("current_owner_type = %s")
            update_params.append("customer")
            update_fields.append("current_owner_customer_id = %s")
            update_params.append(customer_id)

        update_params.append(hardware_id)
        update_query = f"""
            UPDATE hardware_assets
            SET {', '.join(update_fields)}
            WHERE id = %s
            RETURNING *
        """
        hardware = execute_query(update_query, tuple(update_params))
        hardware = hardware[0] if hardware else None
    else:
        insert_query = """
            INSERT INTO hardware_assets (
                asset_type, brand, model, serial_number,
                current_owner_type, current_owner_customer_id,
                notes, eset_uuid, hardware_specs, eset_group
            )
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
            RETURNING *
        """
        insert_params = (
            _eset_detect_asset_type(details),
            brand,
            model,
            serial,
            owner_type,
            customer_id,
            "Imported from ESET",
            device_uuid,
            Json(details),
            group_path
        )
        hardware = execute_query(insert_query, insert_params)
        hardware = hardware[0] if hardware else None

    if hardware and contact_id:
        _upsert_hardware_contact(hardware["id"], contact_id)

    return hardware or {}


@router.get("/hardware/eset/matches", response_model=List[dict])
async def list_eset_matches(limit: int = Query(500, ge=1, le=2000)):
    """List ESET-matched hardware with contact/customer info."""
    query = """
        SELECT
            h.id,
            h.asset_type,
            h.brand,
            h.model,
            h.serial_number,
            h.eset_uuid,
            h.eset_group,
            h.updated_at,
            hc.contact_id,
            c.first_name,
            c.last_name,
            c.user_company,
            cc.customer_id,
            cust.name AS customer_name
        FROM hardware_assets h
        LEFT JOIN hardware_contacts hc ON hc.hardware_id = h.id
        LEFT JOIN contacts c ON c.id = hc.contact_id
        LEFT JOIN contact_companies cc ON cc.contact_id = c.id
        LEFT JOIN customers cust ON cust.id = cc.customer_id
        WHERE h.deleted_at IS NULL
        ORDER BY h.updated_at DESC NULLS LAST
        LIMIT %s
    """
    result = execute_query(query, (limit,))
    return result or []


@router.get("/hardware/eset/incidents", response_model=List[dict])
async def list_eset_incidents(
    severity: Optional[str] = Query("critical"),
    limit: int = Query(200, ge=1, le=2000)
):
    """List cached ESET incidents by severity."""
    severity_list = [s.strip().lower() for s in (severity or "").split(",") if s.strip()]
    if not severity_list:
        severity_list = ["critical"]

    query = """
        SELECT *
        FROM eset_incidents
        WHERE LOWER(COALESCE(severity, '')) = ANY(%s)
        ORDER BY updated_at DESC NULLS LAST
        LIMIT %s
    """
    result = execute_query(query, (severity_list, limit))
    return result or []

