from __future__ import annotations
from contextlib import closing
from datetime import datetime

from pycs import db
from pycs.database.base import NamedBaseModel
from pycs.database.util import commit_on_return

def compare_children(start_label: Label, id: int):
    """ check for cyclic relationships """

    labels_to_check = [start_label]

    while labels_to_check:
        label = labels_to_check.pop(0)

        if label.id == id:
            return False

        labels_to_check.extend(label.children)

    return True

class Label(NamedBaseModel):

    id = db.Column(db.Integer, primary_key=True)
    project_id = db.Column(
        db.Integer,
        db.ForeignKey("project.id", ondelete="CASCADE"),
        nullable=False)

    parent_id = db.Column(
        db.Integer,
        db.ForeignKey("label.id", ondelete="SET NULL"))

    created = db.Column(db.DateTime, default=datetime.utcnow,
        index=True, nullable=False)

    reference = db.Column(db.String)

    # contraints
    __table_args__ = (
        db.UniqueConstraint('project_id', 'reference'),
    )

    # relationships to other models
    parent = db.relationship("Label", backref="children", remote_side=[id])

    @commit_on_return
    def set_parent(self, parent_id: int, commit: bool = True):
        """
        set this labels parent

        :param parent_id: parent's id
        :return:
        """
        if not compare_children(self, parent_id):
            raise ValueError('Cyclic relationship detected!')

        self.parent_id = parent_id
