import requests
import json
import logging

# from poe_new_relic import get_logger
from typing import Any, Iterator, List, Union
# from typeguard import typechecked

class NewRelic:
    def __init__(self, api_key: str, logger: logging.Logger = None):
        self.__logger = logger #or get_logger()
        self._headers = {
            'Accept': 'application/json',
            'API-Key': api_key,
            'Content-Type': 'application/json'
        }
    
    def nerdgraph_query(self, query, output_keys, on = '', next_cursor = None):
        """_summary_
                query New Relic's Nerdgraph api, https://api.newrelic.com/graphiql
        Args:
            query (_type_): _description_
            on (_type_): _description_
            output_keys (_type_): _description_
            next_cursor (_type_, optional): _description_. Defaults to None.

        Returns:
            _type_: _description_
        """
        if next_cursor:
            next_cursor = f'(cursor: "{next_cursor}")'
        full_query = {"query":f"{{\n  actor {{\n    {query} {{\n      results{next_cursor} {{\n        entities {{\n         {on}  {output_keys}\n        }}\n   nextCursor\n   }}\n    }}\n  }}\n}}\n", "variables":""}
        resp = requests.post('https://api.newrelic.com/graphql', headers=self._headers, data=json.dumps(full_query))
        results = json.loads(resp.text)
        return results

    def get_synths(self):
        """_summary_
                cursors over Nerdgraph's entitySearch query results to return every synthetic
        Raises:
            e: _description_
                logs the response back from new relic regarding the query attempt and raises the actual error
        Returns:
            _type_: _description_
                the combined cursored results of all of the synthetics
        """
        entity_search = 'entitySearch(query: \"domain = \u0027SYNTH\u0027 AND type = \u0027MONITOR\u0027\")'
        on = '... on SyntheticMonitorEntityOutline'
        output_keys = '{\n            guid\n            name\n            tags {\n              key\n              values\n            }\n            monitorId\n          }' 
        entities, more, token = [], True, ''
        while more:
            try:
                resp = nr.nerdgraph_query(entity_search, output_keys, on, token)
                results = resp['data']['actor']['entitySearch']['results']
                token = results.get('nextCursor')
                entities.extend(results.get('entities'))
                print(len(entities))
                more = token
            except Exception as e:
                self.__logger.error(f'Failed to start New Relic Nerdgraph query execution: {resp}')
                raise e
        return entities
    
    def get_monitorid_and_guids_synths_by_tag(self, tag):
        """_summary_

        Args:
            tag (_type_): _description_

        Returns:
            _type_: _description_
        """
        wb_tagged = []
        all_synths = nr.get_synths()
        # get only synthetics having said tag
        wb_tagged.extend([i for e in all_synths for i in [','.join(t['values']) for t in e.get('tags') if t['key']==tag]])
        self.__logger.log(f'Found {len(wb_tagged)} entities with tag {tag}')
        # geting distinct set of tags
        set_tags = set(wb_tagged)
        # reducing the  keys down grabbing monitorIds and guids per tag
        panel_entities = [{t:{'monitorId':e.get('monitorId'),'guid':e.get('guid')}} for e in all_synths for t in set_tags for l in [w for w in e.get('tags') if t in w['values']]]
        # grouping tags to array of dicts, {tag:[{monitorId:value, guid:value}]}
        panel_entities = {k: [d.get(k) for d in panel_entities if k in d] for k in set().union(*panel_entities)}
        # creating arrays per monitorId and per guid per tag, {tag:[{monitorId:[values]},{guid:[values]}]} TODO change array of dicts for tags to single dict with the keys
        panel_entities = {g: [{k: [t.get(k) for t in panel_entities.get(g) if k in t] for x in panel_entities.get(g)} for k in set().union(*panel_entities.get(g))] for g in set_tags if panel_entities.get(g)}
        return panel_entities
    
    def get_scorecard_performance_dashboards(self):

        entity_search = 'entitySearch(query: \"((name LIKE \u0027Scorecard -%\u0027) OR (name LIKE \u0027Performance -%\u0027)) AND (domain = \u0027VIZ\u0027 AND type = \u0027DASHBOARD\u0027)\")'
        output_keys = '\n          name\n          permalink\n          type\n        ' 
        dashboards, more, token = [], True, ''
        while more:
            try:
                resp = nr.nerdgraph_query(entity_search, output_keys, next_cursor=token)
                results = resp['data']['actor']['entitySearch']['results']
                token = results.get('nextCursor')
                entities = results.get('entities')
                dashboards.extend(entities)
                print(len(dashboards))
                more = token
            except Exception as e:
                self.__logger.error(f'Failed to start New Relic Nerdgraph query execution: {resp}')
                raise e
        return dashboards


if __name__ == '__main__':

    nr = NewRelic("")
    results = nr.get_scorecard_performance_dashboards()
    # results = nr.get_monitorid_and_guids_synths_by_tag('wallBoardProduct')
    # print(results)
    print(len(results))
    
    