from api.route import Route
from api_graphql.abc.mutation_abc import MutationABC
from api_graphql.field.mutation_field_builder import MutationFieldBuilder
from api_graphql.input.short_url_create_input import ShortUrlCreateInput
from api_graphql.input.short_url_update_input import ShortUrlUpdateInput
from api_graphql.require_any_resolvers import has_assigned_user_spaces
from core.logger import APILogger
from core.string import first_to_lower
from data.schemas.public.domain_dao import domainDao
from data.schemas.public.group_dao import groupDao
from data.schemas.public.short_url import ShortUrl
from data.schemas.public.short_url_dao import shortUrlDao
from data.schemas.public.short_url_visit import ShortUrlVisit
from data.schemas.public.short_url_visit_dao import shortUrlVisitDao
from service.permission.permissions_enum import Permissions

logger = APILogger(__name__)


class ShortUrlMutation(MutationABC):
    def __init__(self):
        MutationABC.__init__(self, "ShortUrl")

        self.field(
            MutationFieldBuilder("create")
            .with_resolver(self.resolve_create)
            .with_input(ShortUrlCreateInput)
            .with_change_broadcast(
                f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
            )
            .with_require_any(
                [Permissions.short_urls_create], [has_assigned_user_spaces]
            )
        )

        self.field(
            MutationFieldBuilder("update")
            .with_resolver(self.resolve_update)
            .with_input(ShortUrlUpdateInput)
            .with_change_broadcast(
                f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
            )
            .with_require_any(
                [Permissions.short_urls_update], [has_assigned_user_spaces]
            )
        )

        self.field(
            MutationFieldBuilder("delete")
            .with_resolver(self.resolve_delete)
            .with_change_broadcast(
                f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
            )
            .with_require_any(
                [Permissions.short_urls_delete], [has_assigned_user_spaces]
            )
        )

        self.field(
            MutationFieldBuilder("restore")
            .with_resolver(self.resolve_restore)
            .with_change_broadcast(
                f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
            )
            .with_require_any(
                [Permissions.short_urls_delete], [has_assigned_user_spaces]
            )
        )

        self.field(
            MutationFieldBuilder("trackVisit")
            .with_resolver(self.resolve_track_visit)
            .with_change_broadcast(
                f"{first_to_lower(self.name.replace("Mutation", ""))}Change"
            )
            .with_require_any_permission([Permissions.short_urls_update])
        )

    @staticmethod
    async def resolve_create(obj: ShortUrlCreateInput, *_):
        logger.debug(f"create short_url: {obj.__dict__}")

        already_exists = await shortUrlDao.find_by({ShortUrl.short_url: obj.short_url})
        if len(already_exists) > 0:
            raise ValueError(f"Short URL {obj.short_url} already exists")

        short_url = ShortUrl(
            0,
            obj.short_url,
            obj.target_url,
            obj.description,
            obj.group_id,
            obj.domain_id,
            obj.loading_screen,
            obj.user_space_id,
        )
        nid = await shortUrlDao.create(short_url)
        return await shortUrlDao.get_by_id(nid)

    @staticmethod
    async def resolve_update(obj: ShortUrlUpdateInput, *_):
        logger.debug(f"update short_url: {input}")

        short_url = await shortUrlDao.get_by_id(obj.id)

        if obj.short_url is not None:
            already_exists = await shortUrlDao.find_by(
                {ShortUrl.short_url: obj.short_url}
            )
            if len(already_exists) > 0:
                raise ValueError(f"Short URL {obj.short_url} already exists")
            short_url.short_url = obj.short_url

        if obj.target_url is not None:
            short_url.target_url = obj.target_url

        if obj.description is not None:
            short_url.description = obj.description

        if obj.group_id is not None:
            group_by_id = await groupDao.find_by_id(obj.group_id)
            if group_by_id is None:
                raise ValueError(f"Group with id {obj.group_id} does not exist")
            short_url.group_id = obj.group_id
        else:
            short_url.group_id = None

        if obj.domain_id is not None:
            domain_by_id = await domainDao.find_by_id(obj.domain_id)
            if domain_by_id is None:
                raise ValueError(f"Domain with id {obj.domain_id} does not exist")
            short_url.domain_id = obj.domain_id
        else:
            short_url.domain_id = None

        if obj.loading_screen is not None:
            short_url.loading_screen = obj.loading_screen

        await shortUrlDao.update(short_url)
        return await shortUrlDao.get_by_id(obj.id)

    @staticmethod
    async def resolve_delete(*_, id: str):
        logger.debug(f"delete short_url: {id}")
        short_url = await shortUrlDao.get_by_id(id)
        await shortUrlDao.delete(short_url)
        return True

    @staticmethod
    async def resolve_restore(*_, id: str):
        logger.debug(f"restore short_url: {id}")
        short_url = await shortUrlDao.get_by_id(id)
        await shortUrlDao.restore(short_url)
        return True

    @staticmethod
    async def resolve_track_visit(*_, id: int, agent: str):
        logger.debug(f"track visit: {id} -- {agent}")
        x = await shortUrlVisitDao.create(ShortUrlVisit(0, id, agent))
        return True
