# --------------------------------------- 
# MCM Device Browser
# --------------------------------------- 
# 
# This module provides device discovery and navigation functionality for MCM
# 
# Key Functions:
# - get_project_config(fc): Scans tag provider and builds a dictionary of all discoverable devices
#   Returns: {tag_path: {"sourceId": path, "name": display_name, "page": page_id}}
# 
# - navigate_to_url(self, source_id, page_id): Navigates to device view and opens detail dock
#   Initiates the device search chain by passing selectDevice and mcm parameters
# 
# Device Discovery Rules:
# - MCM folders (MCMxx): Scans all UDT instances matching MCM_UDT_SUFFIX_PATTERNS
# - Non-MCM folders: Only scans branches containing INCLUDED_UDT_FOLDERS keywords
# - Excludes: UDT types in EXCLUDED_UDT_TYPES list
# - Reads device name from <UDT>/Name tag if available, falls back to instance name
# - Reads page assignment from <UDT>/MCM tag if available, falls back to folder name
# 

import re
import os
import json
import sys

logger = system.util.getLogger("MCM_BROWSER")

EXCLUDED_UDT_TYPES = ("CB_MONITOR", "RACK")
INCLUDED_UDT_FOLDERS = ("Conveyors", "Chute", "Induction")
MCM_UDT_SUFFIX_PATTERNS = (
    # Optional index
#    r"_ENCODER(\d+)?$",
    r"_VFD(\d+)?$",

    # Single index required
    r"_EX\d+$",
    r"_DPM\d+$",
    r"_FIO\d+$",
    r"_FIOH\d+$",
    r"_TPE\d+$",
    r"_EPC\d+$",
    r"_JR\d+$",
    r"_S\d+$",
    r"_SS\d+$",
    r"_PMM\d+$",

    # MCM (single index, no underscore)
    r"(?:^|_)MCM\d+$",
)


def _is_allowed_mcm_udt(name):
    for pattern in MCM_UDT_SUFFIX_PATTERNS:
        if re.search(pattern, name):
            return True
    return False

def _path_has_keyword(path):
    p = path.lower()
    return any(kw.lower() in p for kw in INCLUDED_UDT_FOLDERS)

def _read_device_name(provider, udt_path, fallback):
    """
    Try to read <UDT>/NAME.
    If it exists and is valid, return it.
    Otherwise return fallback.
    """
    try:
        result = system.tag.readBlocking([provider + "/" + udt_path + "/Name"])[0]
        if result.quality.isGood() and result.value:
            return str(result.value)
    except:
        pass
    return fallback

def _read_device_mcm(provider, udt_path):
    """
    Try to read <UDT>/MCM.
    If it exists and is valid, return it.
    Otherwise return None.
    """
    try:
        result = system.tag.readBlocking(
            [provider + "/" + udt_path + "/MCM"]
        )[0]

        if result.quality.isGood() and result.value:
            return str(result.value)

    except:
        pass

    return None


def _browse_area_recursive(provider, basePath, default_page, is_mcm_root):
	global global_project_page_ids
	
	try:
	    children = system.tag.browse(provider + "/" + basePath).getResults()
	except Exception as e:
	    logger.error("Browse FAILED at %s | %s" % (basePath, e))
	    return
	
	for child in children:
	    tagType = str(child.get("tagType", ""))
	    name = str(child.get("name", ""))
	    hasChildren = bool(child.get("hasChildren", False))
	    fullPath = str(child.get("fullPath", ""))
	
	    # Normalize fullPath
	    if fullPath.startswith("[") and "]" in fullPath:
	        fullPath = fullPath.split("]", 1)[1]
		
		if tagType == "UdtInstance":
		    typeId = str(child.get("typeId", ""))
		    udt_name = name  # instance name
		
		    # Skip excluded UDT types
		    if any(excl in typeId for excl in EXCLUDED_UDT_TYPES):
		        continue
		
		    # MCM-specific name filter
		    if default_page.upper().startswith("MCM"):
		        if not _is_allowed_mcm_udt(udt_name):
		            logger.debug(
		                "SKIPPED MCM UDT by name: %s (page=%s)"
		                % (udt_name, default_page)
		            )
		            continue
		
		    display_name = _read_device_name(provider, fullPath, name)
		
		    mcm_override = _read_device_mcm(provider, fullPath)
		    page = mcm_override if mcm_override else default_page
		
		    global_project_page_ids[fullPath] = {
		        "sourceId": fullPath,
		        "name": display_name,
		        "page": page
		    }
		
		    logger.info(
		        "DEVICE FOUND: %s | name=%s | page=%s"
		        % (fullPath, display_name, page)
		    )
		
		    continue
	
	    # Folder recursion rules
	    if tagType == "Folder" and hasChildren:
	        # For MCM roots: recurse everything
	        if is_mcm_root:
	            _browse_area_recursive(provider, fullPath, default_page, True)
	            continue
	
	        # For non-MCM roots: only recurse if path contains keywords
	        if _path_has_keyword(fullPath):
	            _browse_area_recursive(provider, fullPath, default_page, False)
	            continue
	
	        # Otherwise skip this branch
	        # (keeps out Alarm Metrics, etc.)
	        continue

global_project_page_ids = {}

def get_project_config(self):
    global global_project_page_ids

    if global_project_page_ids:
        return global_project_page_ids

    fc = self
    if not fc:
        return {}

    provider = "[" + fc + "_SCADA_TAG_PROVIDER]"
    system_root = "System"

    try:
        system_children = system.tag.browse(provider + "/" + system_root).getResults()
    except:
        return {}

    for child in system_children:
        if str(child.get("tagType", "")) != "Folder":
            continue

        top_name = str(child.get("name", ""))
        top_path = system_root + "/" + top_name

        is_mcm_root = top_name.upper().startswith("MCM")

        # Always scan MCMxx fully
        if is_mcm_root:
            _browse_area_recursive(provider, top_path, top_name, True)
            continue

        # Non-MCM roots: recurse only through keyword branches
        _browse_area_recursive(provider, top_path, top_name, False)

    return global_project_page_ids


def navigate_to_url(self, source_id, page_id):

	view = config.mcm_router.buildViewPath(self.session.custom.fc, page_id)
	
	# Navigate to the view that contains the SVG
	system.perspective.navigate(
	    view=view,
	    params={
	        # pass full SourceId to the view
	        "selectDevice": source_id,
	        "mcm": page_id
	    }
	)
	
	# Open dock with device context
	system.perspective.openDock(
	    id="Docked-East",
	    params={
	        "tagProps": [source_id]
	    }
    )
    

#def reset_highlights(self):
#    self.session.custom.searchId = ""
#    self.session.custom.deviceSearchId = ""
#
#    system.perspective.closePopup(id="TagSearch")
#    system.perspective.closeDock("Docked-East")
#
#    current_page = self.page.props.primaryView
#    system.perspective.navigate(
#        view=current_page,
#        params={"highlightTagPath": "CLEAR"}
#    )
    
    
#def get_current_page_id(self):
#	"""Gets the last segment of the view path"""
#	try:
#		current_view = self.page.props.primaryView
#		if current_view and "/" in current_view:
#			return current_view.split("/")[-1]
#		return current_view
#	except:
#		return None