import validators


class Cluster:
    def __init__(self, uuid, galaxy, description=None, value=None, meta=None):
        self.uuid = uuid
        self.description = description
        self.value = value
        self.meta = meta

        self.galaxy = galaxy  # Reference to the Galaxy object this cluster belongs to
        self.outbound_relationships = set()
        self.inbound_relationships = set()
        self.relationships = set()

    def add_outbound_relationship(self, cluster):
        self.outbound_relationships.add(cluster)

    def add_inbound_relationship(self, cluster):
        self.inbound_relationships.add(cluster)

    def save_relationships(self, relationships):
        self.relationships = relationships

    def generate_entry(self):
        entry = ""
        entry += self._create_title_entry()
        entry += self._create_description_entry()
        entry += self._create_synonyms_entry()
        entry += self._create_uuid_entry()
        entry += self._create_refs_entry()
        entry += self._create_associated_metadata_entry()
        if self.relationships:
            entry += self._create_related_entry()
        return entry

    def _create_title_entry(self):
        entry = ""
        entry += f"## {self.value}\n"
        entry += f"\n"
        return entry

    def _create_description_entry(self):
        entry = ""
        if self.description:
            entry += f"{self.description}\n"
        return entry

    def _create_synonyms_entry(self):
        entry = ""
        if isinstance(self.meta, dict) and self.meta.get("synonyms"):
            entry += f"\n"
            entry += f'??? info "Synonyms"\n'
            entry += f"\n"
            entry += f'     "synonyms" in the meta part typically refer to alternate names or labels that are associated with a particular {self.value}.\n\n'
            entry += f"    | Known Synonyms      |\n"
            entry += f"    |---------------------|\n"
            synonyms_count = 0
            for synonym in sorted(self.meta["synonyms"]):
                synonyms_count += 1
                entry += f"     | `{synonym}`      |\n"
        return entry

    def _create_uuid_entry(self):
        entry = ""
        if self.uuid:
            entry += f"\n"
            entry += f'??? tip "Internal MISP references"\n'
            entry += f"\n"
            entry += f"    UUID `{self.uuid}` which can be used as unique global reference for `{self.value}` in MISP communities and other software using the MISP galaxy\n"
            entry += f"\n"
        return entry

    def _create_refs_entry(self):
        entry = ""
        if isinstance(self.meta, dict) and self.meta.get("refs"):
            entry += f"\n"
            entry += f'??? info "External references"\n'
            entry += f"\n"

            for ref in self.meta["refs"]:
                if validators.url(ref):
                    entry += f"     - [{ref}]({ref}) - :material-archive: :material-arrow-right: [webarchive](https://web.archive.org/web/*/{ref})\n"
                else:
                    entry += f"     - {ref}\n"

            entry += f"\n"
        return entry

    def _create_associated_metadata_entry(self):
        entry = ""
        if isinstance(self.meta, dict):
            excluded_meta = ["synonyms", "refs"]
            entry += f"\n"
            entry += f'??? info "Associated metadata"\n'
            entry += f"\n"
            entry += f"    |Metadata key {{ .no-filter }}      |Value|\n"
            entry += f"    |-----------------------------------|-----|\n"
            for meta in sorted(self.meta.keys()):
                if meta not in excluded_meta:
                    entry += f"    | {meta} | {self.meta[meta]} |\n"
        return entry

    def _create_related_entry(self):
        entry = ""
        entry += f"\n"
        entry += f'??? info "Related clusters"\n'
        entry += f"\n"
        entry += f"    To see the related clusters, click [here](./relations/{self.uuid}.md).\n"
        return entry