# Inspired by
# https://github.com/peopledoc/django-ltree-demo
# https://github.com/mariocesar/django-ltree
from typing import Any

from django.db import models
from django.db.models import fields, Lookup, Transform


class LtreeField(models.TextField):
    description = 'ltree'

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        kwargs['editable'] = False
        kwargs['null'] = True
        kwargs['default'] = None
        super(LtreeField, self).__init__(*args, **kwargs)

    def db_type(self, connection):
        return 'ltree'

    @property
    def db_returning(self) -> bool:
        return True


class BaseLookup(Lookup):
    operator = '='

    def as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = tuple(lhs_params) + tuple(rhs_params)
        return f'{lhs} {self.operator} {rhs}', params


@LtreeField.register_lookup
class Ancestors(BaseLookup):
    lookup_name = 'ancestors'
    operator = '@>'


@LtreeField.register_lookup
class Descendants(BaseLookup):
    lookup_name = 'descendants'
    operator = '<@'


@LtreeField.register_lookup
class Match(BaseLookup):
    lookup_name = 'match'
    operator = '~'


@LtreeField.register_lookup
class MatchSubpath(BaseLookup):
    lookup_name = 'subpath'
    operator = '@'


@LtreeField.register_lookup
class Contains(BaseLookup):
    lookup_name = 'contains'
    operator = '?'


@LtreeField.register_lookup
class NLevel(Transform):
    lookup_name = "depth"
    function = "nlevel"

    @property
    def output_field(self):
        return fields.IntegerField()


__all__ = (
    'LtreeField',
    'Ancestors',
    'Descendants',
    'Match',
    'Contains',
    'NLevel',
)
