# -*- coding: utf-8 -*-
"""
UCMDB Topology Service

This module is the primary engine for retrieving CI and Relationship data 
using pre-defined UCMDB Views. It provides high-level wrappers to handle 
paginated (chunked) result sets automatically.

Exposed Methods:
    get_all_view_results, getChunk, runView
"""

class Topology:
    def __init__(self, server):
        """
        Initialize the service with a reference to the main level UCMDB server
        """
        self.server = server

    def get_all_view_results(self, view_name, chunkSize=10000):
        """
        Executes a view and automatically aggregates all paged chunks.

        This is the recommended method for retrieving large views. It handles 
        the initial request and iterates through all subsequent chunks 
        to provide a single, unified result set.

        Parameters
        ----------
        view_name : str
            The name of the view in UCMDB.
        chunkSize : int, optional
            The number of CIs to retrieve per API call. Default is 10000.

        Returns
        -------
        dict
            A combined dictionary containing 'cis' and 'relations' lists.
        """
        data = self.runView(view_name, chunkSize=chunkSize).json()
        
        all_cis = data.get('cis') or []
        all_relations = data.get('relations') or []
        
        res_id = data.get('queryResultId')
        num_chunks = data.get('numberOfChunks', 0)
        
        if not res_id:
            return {"cis": all_cis, "relations": all_relations}
        
        for i in range(1, num_chunks + 1):
            chunk_data = self.getChunk(res_id, i).json()
            
            all_cis.extend(chunk_data.get('cis') or [])
            all_relations.extend(chunk_data.get('relations') or [])
                
        return {"cis": all_cis, "relations": all_relations}

    def getChunk(self, res_id, index):
        '''
        This method retrieves the values in each chunk (index).

        Parameters
        ----------
        res_id : str
            The temporary result identifier (queryResultId) from the initial call.
        index : int
            Which chunk to get.

        Returns
        -------
        requests.Response
            Can be converted to a dictionary containing the CIs and relations. For example:
                {
                "cis": [
                    {
                    "ucmdbId": "4fc4d26b423c52bd99c3586017fd55e7",
                    "globalId": null,
                    "type": "nt",
                    "properties": {
                        "display_label": "pue01vm0040"
                    },
                    "attributesDisplayNames": null,
                    "attributesQualifiers": null,
                    "attributesType": null,
                    "classDefinition": null,
                    "displayLabel": null,
                    "label": "Windows"
                    },
                    {
                    "ucmdbId": "4fe8814b30be8ca4aeedcf1e4323fa62",
                    "globalId": null,
                    "type": "nt",
                    "properties": {
                        "display_label": "pue01vm1278"
                    },
                    "attributesDisplayNames": null,
                    "attributesQualifiers": null,
                    "attributesType": null,
                    "classDefinition": null,
                    "displayLabel": null,
                    "label": "Windows"
                    },
                    {
                    "ucmdbId": "4fee7d96a41be2f48f7fd343e815b6de",
                    "globalId": null,
                    "type": "nt",
                    "properties": {
                        "display_label": "bra03pc78"
                    },
                    "attributesDisplayNames": null,
                    "attributesQualifiers": null,
                    "attributesType": null,
                    "classDefinition": null,
                    "displayLabel": null,
                    "label": "Windows"
                    }
                ],
                "relations": []
                }
        '''
        url_part = f'/topology/result/{res_id}/{index}'
        return self.server._request("GET",url_part)

    def getChunkForPath(self, state, execution_id, chunk):
        """
        Retrieves a chunk of data for a specific path from the UCMDB server.

        This method makes a POST request to the UCMDB server to retrieve a 
        chunk of data for a specific path.

        Parameters
        ----------
        state : str
            The path element ID.
        execution_id : str
            The ID of the view execution.
        chunk : int
            The number of the chunk to retrieve.

        Returns
        -------
        requests.Response
            Response object containing the requested chunk of data.
        """
        body = {
            "viewExecutionId": execution_id,
            "path": [{"pathElementId": state, "pathElementType": state}],
            "chunkNumber": chunk
        }
        url_part = '/uiserver/modeling/views/result/chunkForPath'
        return self.server._request("POST",url_part,json=body)

    def queryCIs(self, query):
        '''
        Retrieves the result of a query defined in UCMDB via a REST API POST 
        call.

        Parameters
        ----------
        query : dict
            JSON describing the query. For example:
                {
                    "nodes": [
                        {
                            "type": "node",
                            "queryIdentifier": "node",
                            "visible": "true",
                            "includeSubtypes": "true",
                            "layout": ["display_label"],
                            "attributeConditions": [],
                            "linkConditions": [],
                            "ids": []
                        }
                    ],
                    "relations": []
                }

        Returns
        -------
        requests.Response
            Can be converted to a dictionary containing 2 entries, a list of CIs (dictionaries)
            and a list of relations (also dictionaries). For example:
                {
                    "cis": [],
                    "relations": []
                }
        '''
        url_part = '/topologyQuery'
        return self.server._request("POST",url_part,json=query)

    def runView(self, view, includeEmptyLayout=False, chunkSize=10000):
        '''
        Retrieves the result of a view defined in UCMDB via a REST API POST 
        call

        Parameters
        ----------
        view : str
            Name of a view on the UCMDB server.
        includeEmptyLayout : bool
            Should empty layouts be shown? Default is False.
        chunkSize : int
            The max number of nodes to return in each chunk.

        Returns
        -------
        requests.Response
            Can be converted to a dictionary contains 2 entries, CIs and Relations, each of
            which is a list of dictionaries. For example:
                {
                    "cis": [],
                    "relations": []
                }
        '''
        url_part = '/topology'
        payload = {"includeEmptyLayoutProperties": includeEmptyLayout, "chunkSize": chunkSize}
        return self.server._request("POST", url_part, json=view, params=payload)